lib/msf/core/modules/external/cli.rb
# -*- coding: binary -*-
# CLI for interaction with modules outside of msfconsole
require 'optparse'
module Msf::Modules::External::CLI
def self.parse_options(mod)
action = 'run'
actions = ['run'] + mod.meta['capabilities']
args = mod.meta['options'].reduce({}) do |defaults, (n, opt)|
if opt['default'].nil?
if opt['required']
defaults
else
defaults[n] = nil
defaults
end
else
defaults[n] = opt['default']
defaults
end
end
op = OptionParser.new do |opts|
if $0 != mod.path
opts.banner = "Usage: #{$0} #{mod.path} [OPTIONS] [ACTION]"
end
opts.separator ""
opts.separator mod.meta['description']
opts.separator ""
opts.separator "Postitional arguments:"
opts.separator " ACTION: The action to take (#{actions.inspect})"
opts.separator ""
opts.separator "Required arguments:"
make_options opts, args, mod.meta['options'].select {|n, o| o['required'] && o['default'].nil?}
opts.separator ""
opts.separator "Optional arguments:"
make_options opts, args, mod.meta['options'].select {|n, o| !o['required'] || !o['default'].nil?}
opts.on '-h', '--help', 'Prints this help' do
$stderr.puts opts
exit
end
end
begin
extra = op.permute *ARGV
# If no extra args are given we use the default action
if extra.length == 1
action = extra.shift
elsif extra.length > 1
action = extra.shift
$stderr.puts "WARNING: unrecognized arguments #{extra.inspect}"
end
rescue OptionParser::InvalidArgument => e
$stderr.puts e.message
abort
rescue OptionParser::MissingArgument => e
$stderr.puts e.message
abort
end
required = mod.meta['options'].select {|_, o| o['required']}.map {|n, _| n}.sort
# Were we run with any non-module options if we need them?
if args.empty? && !required.empty?
$stderr.puts op
exit
# Did someone forget to add some options we need?
elsif (args.keys & required).sort != required
missing = required - (args.keys & required)
abort "Missing required option(s): #{missing.map {|o| '--' + o}.join ', '}"
end
unless action == 'run' || mod.meta['capabilities'].include?(action)
$stderr.puts "Invalid ACTION choice #{action.inspect} (choose from #{actions.inspect})"
abort
end
action =
case action
when 'run'; :run
when 'soft_check'; :soft_check
when 'hard_check'; :hard_check
end
[args, action]
end
def self.choose_type(t)
if t == 'int' or t == 'port'
Integer
elsif t == 'float'
Float
elsif t.match /range$/
Array
else # XXX TODO add validation for addresses and other MSF option types
String
end
end
def self.make_options(parser, out, args)
args.each do |n, opt|
name = n.tr('_', '-')
desc = if opt['default']
"#{opt['description']}, (default: #{opt['default']})"
else
opt['description']
end
parser.on "--#{name} #{n.upcase}", choose_type(opt['type']), desc do |arg|
out[n] = arg
end
end
end
end