use ruby Net::SSH to read a remote file via sudo

2019-04-10 22:43发布

I have to read the contents of a remote file I have permissions to (sudo) read with cat,less or tail.

I am going to be doing this in Ruby so I assume I should be using Net::SSH to do it.

The file is a log file so it can be quite big.

This is the code I am trying now:

require 'rubygems'
require 'net/ssh'

cmd = "sudo cat /var/logs/httpd/ACCESS_log.2012.03.23"

Net::SSH.start( "SERVER" , "USER", :password => "PASSWORD") do |ssh|
  ssh.open_channel do |channel|
    channel.request_pty
     channel.exec(cmd);

     channel.on_close do
       puts "shell terminated"
     end
    channel.on_eof do |ch|
      puts "remote end is done sending data"
    end
    channel.on_extended_data do |ch, type, data|
      puts "got stderr: #{data.inspect}"
    end
    channel.on_data do |channel, data|
      if data =~ /^\[sudo\] password for USER:/
        puts "data works"
        channel.send_data 'PASSWORD'
      end
     channel.on_data do |ch,data|
        puts "in third"
        puts data.inspect
     end
    end
   channel.on_process do |ch|
     puts "in process"
   end
  ssh.loop
  end
end

When I run that I get the following output:

in process in process in process data works in process in process in process in third "\r\n" remote end is done sending data shell terminated

The log actually currently has a few thousand lines of data in it, because I can read it from the actual server using putty.

How do I get that out from channel.on_data ?

Thanks

标签: ruby ssh
3条回答
Viruses.
2楼-- · 2019-04-10 22:53

I think you need to add a \n to the password you send. This works for me. Note, The place where I commented out the else clause, you could possibly get the info from there too, but it works as you have it, but with a \n in the password.

require 'rubygems'
require 'net/ssh'

cmd = "sudo cat /var/log/mail.log"
HOSTNAME = "myhost.example.com"
USERNAME = "me"
PASSWORD = "12345"


Net::SSH.start( HOSTNAME , USERNAME, :password => PASSWORD) do |ssh|
  ssh.open_channel do |channel|
    channel.request_pty
     channel.exec(cmd);

     channel.on_close do
       puts "shell terminated"
     end
    channel.on_eof do |ch|
      puts "remote end is done sending data"
    end
    channel.on_extended_data do |ch, type, data|
      puts "got stderr: #{data.inspect}"
    end
    channel.on_data do |channel, data|
      if data =~ /^\[sudo\] password for #{USERNAME}:/
        puts "data works"
        channel.send_data "#{PASSWORD}\n"
      else
        #puts "OUTPUT NOT MATCHED: #{data}"
      end
       channel.on_data do |ch,data|
         puts "in third"
        puts data.inspect
       end
    end
   channel.on_process do |ch|
     puts "in process"
   end
  ssh.loop
  end
end
查看更多
Evening l夕情丶
3楼-- · 2019-04-10 22:59
require 'net/ssh'

Net::SSH.start('host', 'user', :password => "password") do |ssh|
  # capture all stderr and stdout output from a remote process
  output = ssh.exec!("hostname")
  puts output

  # capture only stdout matching a particular pattern
  stdout = ""
  ssh.exec!("ls -l /home/jamis") do |channel, stream, data|
    stdout << data if stream == :stdout
  end
  puts stdout

  # run multiple processes in parallel to completion
  ssh.exec "sed ..."
  ssh.exec "awk ..."
  ssh.exec "rm -rf ..."
  ssh.loop

  # open a new channel and configure a minimal set of callbacks, then run
  # the event loop until the channel finishes (closes)
  channel = ssh.open_channel do |ch|
    ch.exec "/usr/local/bin/ruby /path/to/file.rb" do |ch, success|
      raise "could not execute command" unless success

      # "on_data" is called when the process writes something to stdout
      ch.on_data do |c, data|
        $stdout.print data
      end

      # "on_extended_data" is called when the process writes something to stderr
      ch.on_extended_data do |c, type, data|
        $stderr.print data
      end

      ch.on_close { puts "done!" }
    end
  end

  channel.wait

  # forward connections on local port 1234 to port 80 of www.capify.org
  ssh.forward.local(1234, "www.capify.org", 80)
  ssh.loop { true }
end

Latest Document 17.11.25

查看更多
聊天终结者
4楼-- · 2019-04-10 23:16

You are replacing a new on_data callback while executing an on_data callback. I haven't spelunked the internals of Net::SSH, but that could produce surprising behavior.

Try changing your code in your two on_data callbacks to be one, and see if that helps.

channel.on_data do |channel, data|
  if data =~ /^\[sudo\] password for USER:/
    puts "data works"
    channel.send_data 'PASSWORD'
  else
    puts "in third"
    puts data.inspect
  if
end

As a side note, since you need sudo to read the logs, someone thinks they and that server are worth protecting. It looks like you're embedding passwords which give privileged access to the server in this ruby program. That implies anyone who can read the program gains the same privileged access. What will you do to limit access to the password in this program?

查看更多
登录 后发表回答