module Rex::Ui::Text::Shell

The shell class provides a command-prompt style interface in a generic fashion.

Attributes

disable_output[RW]

Whether or not output has been disabled.

framework[RW]
hist_last_saved[RW]
input[R]

The input handle to read user input from.

on_command_proc[RW]
on_print_proc[RW]
output[R]

The output handle to write output to.

Public Class Methods

new(prompt, prompt_char = '>', histfile = nil, framework = nil) click to toggle source

Initializes a shell that has a prompt and can be interacted with.

# File lib/rex/ui/text/shell.rb, line 40
def initialize(prompt, prompt_char = '>', histfile = nil, framework = nil)
  # Set the stop flag to false
  self.stop_flag      = false
  self.disable_output = false
  self.stop_count         = 0

  # Initialize the prompt
  self.init_prompt = prompt
  self.prompt_char = prompt_char

  self.histfile = histfile
  self.hist_last_saved = 0

  self.framework = framework
end

Public Instance Methods

init_tab_complete() click to toggle source
# File lib/rex/ui/text/shell.rb, line 56
def init_tab_complete
  if (self.input and self.input.supports_readline)
    self.input = Input::Readline.new(lambda { |str| tab_complete(str) })
    if Readline::HISTORY.length == 0 and histfile and File.exists?(histfile)
      File.readlines(histfile).each { |e|
        Readline::HISTORY << e.chomp
      }
      self.hist_last_saved = Readline::HISTORY.length
    end
    self.input.output = self.output
    update_prompt(input.prompt)
  end
end
init_ui(in_input = nil, in_output = nil) click to toggle source

Initializes the user interface input/output classes.

# File lib/rex/ui/text/shell.rb, line 73
def init_ui(in_input = nil, in_output = nil)
  # Initialize the input and output methods
  self.input  = in_input
  self.output = in_output

  if (self.input)
    # Extend the input medium as an input shell if the input medium
    # isn't intrinsicly a shell.
    if (self.input.intrinsic_shell? == false)
      self.input.extend(InputShell)
    end

    self.input.output = self.output
  end
  update_prompt('')
end
print(msg='') click to toggle source

Prints a raw message to the output handle.

print_error(msg='') click to toggle source

Prints an error message to the output handle.

print_good(msg='') click to toggle source

Prints a good message to the output handle.

print_line(msg='') click to toggle source

Prints a line of text to the output handle.

print_status(msg='') click to toggle source

Prints a status message to the output handle.

print_warning(msg='') click to toggle source

Prints a warning message to the output handle.

reset_ui() click to toggle source

Resets the user interface handles.

# File lib/rex/ui/text/shell.rb, line 93
def reset_ui
  init_ui
end
run(&block) click to toggle source

Run the command processing loop.

# File lib/rex/ui/text/shell.rb, line 121
def run(&block)

  begin

    while true
      # If the stop flag was set or we've hit EOF, break out
      break if (self.stop_flag or self.stop_count > 1)

      init_tab_complete

      if framework
        if input.prompt.include?("%T")
          t = Time.now
          if framework.datastore['PromptTimeFormat']
            t = t.strftime(framework.datastore['PromptTimeFormat'])
          end
          input.prompt.gsub!(/%T/, t.to_s)
        end

        if input.prompt.include?("%H")
          hostname = ENV['HOSTNAME']
          if hostname.nil?
            hostname = `hostname`.split('.')[0]
          end

          # check if hostname is still nil
          if hostname.nil?
            hostname = ENV['COMPUTERNAME']
          end

          if hostname.nil?
            hostname = 'unknown'
          end

          input.prompt.gsub!(/%H/, hostname.chomp)
        end

        if input.prompt.include?("%U")
          user = ENV['USER']
          if user.nil?
            user = `whoami`
          end

          # check if username is still nil
          if user.nil?
            user = ENV['USERNAME']
          end

          if user.nil?
            user = 'unknown'
          end

          input.prompt.gsub!(/%U/, user.chomp)
        end

        input.prompt.gsub!(/%S/, framework.sessions.length.to_s)
        input.prompt.gsub!(/%J/, framework.jobs.length.to_s)
        input.prompt.gsub!(/%L/, Rex::Socket.source_address("50.50.50.50"))
        input.prompt.gsub!(/%D/, ::Dir.getwd)
        if framework.db.active
          input.prompt.gsub!(/%W/, framework.db.workspace.name)
        end
        self.init_prompt = input.prompt
      end

      line = input.pgets()
      log_output(input.prompt)

      # If a block was passed in, pass the line to it.  If it returns true,
      # break out of the shell loop.
      if (block)
        break if (line == nil or block.call(line))
      elsif(input.eof? or line == nil)
      # If you have sessions active, this will give you a shot to exit gravefully
      # If you really are ambitious, 2 eofs will kick this out
        self.stop_count += 1
        next if(self.stop_count > 1)
        run_single("quit")
      else
      # Otherwise, call what should be an overriden instance method to
      # process the line.
        ret = run_single(line)
        # don't bother saving lines that couldn't be found as a
        # command, create the file if it doesn't exist
        if ret and self.histfile
          File.open(self.histfile, "a+") { |f|
            f.puts(line)
          }
        end
        self.stop_count = 0
      end

    end
  # Prevent accidental console quits
  rescue ::Interrupt
    output.print("Interrupt: use the 'exit' command to quit\n")
    retry
  end
end
set_log_source(log_source) click to toggle source

Sets the log source that should be used for logging input and output.

# File lib/rex/ui/text/shell.rb, line 100
def set_log_source(log_source)
  self.log_source = log_source
end
stop() click to toggle source

Stop processing user input.

# File lib/rex/ui/text/shell.rb, line 224
def stop
  self.stop_flag = true
end
stopped?() click to toggle source

Checks to see if the shell has stopped.

# File lib/rex/ui/text/shell.rb, line 231
def stopped?
  self.stop_flag
end
tab_complete(str) click to toggle source

Performs tab completion on the supplied string.

# File lib/rex/ui/text/shell.rb, line 114
def tab_complete(str)
  return tab_complete_proc(str) if (tab_complete_proc)
end
unset_log_source() click to toggle source

Unsets the log source so that logging becomes disabled.

# File lib/rex/ui/text/shell.rb, line 107
def unset_log_source
  set_log_source(nil)
end
update_prompt(prompt = nil, new_prompt_char = nil, mode = false) click to toggle source

Change the input prompt.

prompt - the actual prompt new_prompt_char the char to append to the prompt mode - append or not to append - false = append true = make a new prompt

# File lib/rex/ui/text/shell.rb, line 241
def update_prompt(prompt = nil, new_prompt_char = nil, mode = false)
  if (self.input)
    if prompt
      new_prompt = self.init_prompt + ' ' + prompt + prompt_char + ' '
    else
      new_prompt = self.prompt || ''
    end

    if mode
      new_prompt = prompt + (new_prompt_char || prompt_char) + ' '
    end

    # Save the prompt before any substitutions
    self.prompt = new_prompt

    # Set the actual prompt to the saved prompt with any substitutions
    # or updates from our output driver, be they color or whatever
    self.input.prompt = self.output.update_prompt(new_prompt)
    self.prompt_char  = new_prompt_char if (new_prompt_char)
  end
end

Protected Instance Methods

_print_prompt(prompt) click to toggle source

Print the prompt, but do not log it.

# File lib/rex/ui/text/shell.rb, line 366
def _print_prompt(prompt)
  output.print(prompt)
end
log_input(buf) click to toggle source

Writes the supplied input to the log source if one has been registered.

# File lib/rex/ui/text/shell.rb, line 373
def log_input(buf)
  rlog(buf, log_source) if (log_source)
end
log_output(buf) click to toggle source

Writes the supplied output to the log source if one has been registered.

# File lib/rex/ui/text/shell.rb, line 380
def log_output(buf)
  rlog(buf, log_source) if (log_source)
end
parse_line(line) click to toggle source

Parse a line into an array of arguments.

# File lib/rex/ui/text/shell.rb, line 349
def parse_line(line)
  log_input(line)

  line.gsub!(/(\r|\n)/, '')

  begin
    return args = Rex::Parser::Arguments.from_s(line)
  rescue ::ArgumentError
    print_error("Parse error: #{$!}")
  end

  return []
end