Files
metasploit-gs/lib/msf/ui/console/driver.rb
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

728 lines
20 KiB
Ruby
Raw Normal View History

# -*- coding: binary -*-
require 'find'
require 'erb'
require 'rexml/document'
require 'fileutils'
2011-11-09 21:40:02 -06:00
require 'digest/md5'
2005-07-07 06:14:58 +00:00
2005-05-22 19:39:21 +00:00
module Msf
module Ui
module Console
#
# A user interface driver on a console interface.
2005-05-22 19:39:21 +00:00
#
class Driver < Msf::Ui::Driver
2005-10-02 03:21:26 +00:00
ConfigCore = "framework/core"
ConfigGroup = "framework/ui/console"
2013-08-30 16:28:33 -05:00
DefaultPrompt = "%undmsf#{Metasploit::Framework::Version::MAJOR}%clr"
DefaultPromptChar = "%clr>"
2013-08-30 16:28:33 -05:00
2016-12-05 09:12:52 -06:00
#
# Console Command Dispatchers to be loaded after the Core dispatcher.
#
CommandDispatchers = [
2016-12-05 10:30:18 -06:00
CommandDispatcher::Modules,
2016-12-05 09:20:07 -06:00
CommandDispatcher::Jobs,
2018-04-10 18:31:02 -04:00
CommandDispatcher::Resource,
CommandDispatcher::Db,
CommandDispatcher::Creds,
2023-11-02 19:44:04 +11:00
CommandDispatcher::Developer,
CommandDispatcher::DNS
2016-12-05 09:12:52 -06:00
]
2005-07-16 08:12:58 +00:00
#
# The console driver processes various framework notified events.
#
include FrameworkEventManager
2013-08-30 16:28:33 -05:00
2005-07-16 08:12:58 +00:00
#
# The console driver is a command shell.
#
2005-07-18 05:13:21 +00:00
include Rex::Ui::Text::DispatcherShell
2013-08-30 16:28:33 -05:00
2018-07-09 11:27:30 +08:00
include Rex::Ui::Text::Resource
2005-11-15 15:11:43 +00:00
#
# Initializes a console driver instance with the supplied prompt string and
2005-11-28 16:36:06 +00:00
# prompt character. The optional hash can take extra values that will
# serve to initialize the console driver.
2005-11-15 15:11:43 +00:00
#
# @option opts [Boolean] 'AllowCommandPassthru' (true) Whether to allow
# unrecognized commands to be executed by the system shell
2022-02-12 21:32:24 +00:00
# @option opts [Boolean] 'Readline' (true) Whether to use the readline or not
# @option opts [Boolean] 'RealReadline' (false) Whether to use the system's
# readline library instead of RBReadline
# @option opts [String] 'HistFile' (Msf::Config.history_file) Path to a file
# where we can store command history
# @option opts [Array<String>] 'Resources' ([]) A list of resource files to
# load. If no resources are given, will load the default resource script,
# 'msfconsole.rc' in the user's {Msf::Config.config_directory config
# directory}
# @option opts [Boolean] 'SkipDatabaseInit' (false) Whether to skip
# connecting to the database and running migrations
2005-11-28 16:36:06 +00:00
def initialize(prompt = DefaultPrompt, prompt_char = DefaultPromptChar, opts = {})
2014-10-29 22:33:23 -05:00
choose_readline(opts)
2013-08-30 16:28:33 -05:00
histfile = opts['HistFile'] || Msf::Config.history_file
2013-08-30 16:28:33 -05:00
begin
FeatureManager.instance.load_config
rescue StandardError => e
elog(e)
end
if opts['DeferModuleLoads'].nil?
opts['DeferModuleLoads'] = Msf::FeatureManager.instance.enabled?(Msf::FeatureManager::DEFER_MODULE_LOADS)
end
2011-07-21 06:14:25 +00:00
# Initialize attributes
2014-12-02 10:28:23 -06:00
framework_create_options = opts.merge({ 'DeferModuleLoads' => true })
if Msf::FeatureManager.instance.enabled?(Msf::FeatureManager::DNS)
dns_resolver = Rex::Proto::DNS::CachedResolver.new
dns_resolver.extend(Rex::Proto::DNS::CustomNameserverProvider)
2024-02-07 15:26:13 -05:00
dns_resolver.load_config if dns_resolver.has_config?
# Defer loading of modules until paths from opts can be added below
framework_create_options = framework_create_options.merge({ 'CustomDnsResolver' => dns_resolver })
end
2014-12-02 10:28:23 -06:00
self.framework = opts['Framework'] || Msf::Simple::Framework.create(framework_create_options)
2013-08-30 16:28:33 -05:00
2011-07-21 06:14:25 +00:00
if self.framework.datastore['Prompt']
prompt = self.framework.datastore['Prompt']
2011-07-21 14:35:02 +00:00
prompt_char = self.framework.datastore['PromptChar'] || DefaultPromptChar
2011-07-21 06:14:25 +00:00
end
2013-08-30 16:28:33 -05:00
2005-07-18 05:13:21 +00:00
# Call the parent
2021-05-21 16:24:05 -04:00
super(prompt, prompt_char, histfile, framework, :msfconsole)
2013-08-30 16:28:33 -05:00
2005-10-30 23:40:27 +00:00
# Temporarily disable output
self.disable_output = true
2013-08-30 16:28:33 -05:00
2005-10-30 23:40:27 +00:00
# Load pre-configuration
load_preconfig
2013-08-30 16:28:33 -05:00
2005-11-28 16:36:06 +00:00
# Initialize the user interface to use a different input and output
# handle if one is supplied
input = opts['LocalInput']
input ||= Rex::Ui::Text::Input::Stdio.new
2013-08-30 16:28:33 -05:00
2022-02-12 21:32:24 +00:00
if !opts['Readline']
input.disable_readline
end
if (opts['LocalOutput'])
2010-12-29 00:35:27 +00:00
if (opts['LocalOutput'].kind_of?(String))
output = Rex::Ui::Text::Output::File.new(opts['LocalOutput'])
else
2010-12-29 00:35:27 +00:00
output = opts['LocalOutput']
end
else
output = Rex::Ui::Text::Output::Stdio.new
2005-11-28 16:36:06 +00:00
end
2013-08-30 16:28:33 -05:00
init_ui(input, output)
init_tab_complete
2013-08-30 16:28:33 -05:00
2005-05-22 19:39:21 +00:00
# Add the core command dispatcher as the root of the dispatcher
# stack
enstack_dispatcher(CommandDispatcher::Core)
2013-08-30 16:28:33 -05:00
# Report readline error if there was one..
2014-10-29 22:33:23 -05:00
if !@rl_err.nil?
print_error("***")
2020-04-14 15:08:58 -05:00
print_error("* Unable to load readline: #{@rl_err}")
print_error("* Falling back to RbReadLine")
print_error("***")
end
2013-08-30 16:28:33 -05:00
2016-12-05 09:12:52 -06:00
# Load the other "core" command dispatchers
2021-03-23 13:26:45 +00:00
CommandDispatchers.each do |dispatcher_class|
dispatcher = enstack_dispatcher(dispatcher_class)
dispatcher.load_config(opts['Config'])
2016-12-05 09:12:52 -06:00
end
2013-08-30 16:28:33 -05:00
2018-04-10 18:31:02 -04:00
if !framework.db || !framework.db.active
if framework.db.error == "disabled"
2020-04-14 15:08:58 -05:00
print_warning("Database support has been disabled")
else
2018-04-10 18:31:02 -04:00
error_msg = "#{framework.db.error.class.is_a?(String) ? "#{framework.db.error.class} " : nil}#{framework.db.error}"
2020-04-14 15:08:58 -05:00
print_warning("No database support: #{error_msg}")
end
end
2013-08-30 16:28:33 -05:00
2005-07-16 08:12:58 +00:00
# Register event handlers
register_event_handlers
2013-08-30 16:28:33 -05:00
2005-10-02 03:21:26 +00:00
# Re-enable output
self.disable_output = false
2013-08-30 16:28:33 -05:00
2005-12-07 03:06:31 +00:00
# Whether or not command passthru should be allowed
2016-03-15 20:58:14 -05:00
self.command_passthru = opts.fetch('AllowCommandPassthru', true)
2013-08-30 16:28:33 -05:00
# Whether or not to confirm before exiting
self.confirm_exit = opts['ConfirmExit']
2014-12-02 14:41:32 -06:00
# Initialize the module paths only if we didn't get passed a Framework instance and 'DeferModuleLoads' is false
unless opts['Framework']
# Configure the framework module paths
self.framework.init_module_paths(module_paths: opts['ModulePath'], defer_module_loads: opts['DeferModuleLoads'])
end
2013-08-30 16:28:33 -05:00
unless opts['DeferModuleLoads']
framework.threads.spawn("ModuleCacheRebuild", true) do
framework.modules.refresh_cache_from_module_files
end
end
2013-08-30 16:28:33 -05:00
# Load console-specific configuration (after module paths are added)
load_config(opts['Config'])
2013-08-30 16:28:33 -05:00
# Process things before we actually display the prompt and get rocking
on_startup(opts)
2013-08-30 16:28:33 -05:00
# Process any resource scripts
2014-08-28 16:27:23 -05:00
if opts['Resource'].blank?
# None given, load the default
default_resource = ::File.join(Msf::Config.config_directory, 'msfconsole.rc')
2016-04-20 08:11:34 -04:00
load_resource(default_resource) if ::File.exist?(default_resource)
else
opts['Resource'].each { |r|
load_resource(r)
}
end
2013-08-30 16:28:33 -05:00
2018-06-25 05:32:17 -04:00
# Process persistent job handler
begin
restore_handlers = JSON.parse(File.read(Msf::Config.persist_file))
rescue Errno::ENOENT, JSON::ParserError
restore_handlers = nil
end
2018-06-25 05:32:17 -04:00
2018-08-21 03:05:44 +00:00
if restore_handlers
print_status("Starting persistent handler(s)...")
2018-06-25 05:32:17 -04:00
restore_handlers.each do |handler_opts|
2018-06-25 05:32:17 -04:00
handler = framework.modules.create(handler_opts['mod_name'])
handler.exploit_simple(handler_opts['mod_options'])
2018-06-25 05:32:17 -04:00
end
end
# Process any additional startup commands
2012-09-20 13:34:29 -05:00
if opts['XCommands'] and opts['XCommands'].kind_of? Array
opts['XCommands'].each { |c|
run_single(c)
}
end
end
2013-08-30 16:28:33 -05:00
2005-10-30 23:40:27 +00:00
#
# Loads configuration that needs to be analyzed before the framework
# instance is created.
#
def load_preconfig
begin
conf = Msf::Config.load
rescue
wlog("Failed to load configuration: #{$!}")
return
end
2013-08-30 16:28:33 -05:00
2005-10-30 23:40:27 +00:00
if (conf.group?(ConfigCore))
conf[ConfigCore].each_pair { |k, v|
on_variable_set(true, k, v)
}
end
end
2013-08-30 16:28:33 -05:00
#
2005-11-15 15:11:43 +00:00
# Loads configuration for the console.
#
2006-04-02 16:28:02 +00:00
def load_config(path=nil)
begin
2006-04-02 16:28:02 +00:00
conf = Msf::Config.load(path)
rescue
wlog("Failed to load configuration: #{$!}")
return
end
2013-08-30 16:28:33 -05:00
# If we have configuration, process it
if (conf.group?(ConfigGroup))
conf[ConfigGroup].each_pair { |k, v|
2005-10-02 03:21:26 +00:00
case k.downcase
when 'activemodule'
run_single("use #{v}")
when 'activeworkspace'
if framework.db.active
workspace = framework.db.find_workspace(v)
2015-04-03 16:44:36 -05:00
framework.db.workspace = workspace if workspace
end
end
}
end
end
2013-08-30 16:28:33 -05:00
#
2020-05-11 10:22:20 +01:00
# Generate configuration for the console.
#
2020-05-11 10:22:20 +01:00
def get_config
# Build out the console config group
group = {}
2013-08-30 16:28:33 -05:00
if (active_module)
group['ActiveModule'] = active_module.fullname
end
2013-08-30 16:28:33 -05:00
if framework.db.active
unless framework.db.workspace.default?
group['ActiveWorkspace'] = framework.db.workspace.name
end
end
2020-05-11 10:22:20 +01:00
group
end
def get_config_core
ConfigCore
end
def get_config_group
ConfigGroup
end
#
# Saves configuration for the console.
#
def save_config
begin
2020-05-11 10:22:20 +01:00
Msf::Config.save(ConfigGroup => get_config)
2009-03-08 07:41:28 +00:00
rescue ::Exception
print_error("Failed to save console config: #{$!}")
end
end
2013-08-30 16:28:33 -05:00
#
# Saves the recent history to the specified file
#
def save_recent_history(path)
num = Readline::HISTORY.length - hist_last_saved - 1
2013-08-30 16:28:33 -05:00
tmprc = ""
num.times { |x|
tmprc << Readline::HISTORY[hist_last_saved + x] + "\n"
}
2013-08-30 16:28:33 -05:00
if tmprc.length > 0
print_status("Saving last #{num} commands to #{path} ...")
save_resource(tmprc, path)
else
print_error("No commands to save!")
end
2013-08-30 16:28:33 -05:00
# Always update this, even if we didn't save anything. We do this
# so that we don't end up saving the "makerc" command itself.
self.hist_last_saved = Readline::HISTORY.length
end
2013-08-30 16:28:33 -05:00
2006-04-02 16:28:02 +00:00
#
# Creates the resource script file for the console.
#
def save_resource(data, path=nil)
path ||= File.join(Msf::Config.config_directory, 'msfconsole.rc')
2013-08-30 16:28:33 -05:00
2006-04-02 16:28:02 +00:00
begin
rcfd = File.open(path, 'w')
rcfd.write(data)
rcfd.close
2008-11-11 06:00:54 +00:00
rescue ::Exception
2006-04-02 16:28:02 +00:00
end
end
2013-08-30 16:28:33 -05:00
2005-07-14 07:13:01 +00:00
#
# Called before things actually get rolling such that banners can be
# displayed, scripts can be processed, and other fun can be had.
#
def on_startup(opts = {})
# Check for modules that failed to load
2012-10-04 16:32:12 -05:00
if framework.modules.module_load_error_by_path.length > 0
wlog("The following modules could not be loaded!")
2013-08-30 16:28:33 -05:00
framework.modules.module_load_error_by_path.each do |path, _error|
wlog("\t#{path}")
end
2012-12-05 12:30:55 -06:00
end
2013-08-30 16:28:33 -05:00
2015-12-29 10:37:09 +01:00
if framework.modules.module_load_warnings.length > 0
print_warning("The following modules were loaded with warnings:")
framework.modules.module_load_warnings.each do |path, _error|
wlog("\t#{path}")
2015-12-29 10:37:09 +01:00
end
end
2020-12-09 14:47:22 +00:00
if framework.db&.active
framework.db.workspace = framework.db.default_workspace unless framework.db.workspace
end
2015-12-29 10:37:09 +01:00
framework.events.on_ui_start(Msf::Framework::Revision)
2013-08-30 16:28:33 -05:00
2014-10-14 14:54:45 -05:00
if $msf_spinner_thread
$msf_spinner_thread.kill
2015-06-06 15:56:42 -05:00
$stderr.print "\r" + (" " * 50) + "\n"
2014-10-14 14:54:45 -05:00
end
run_single("banner") unless opts['DisableBanner']
2013-08-30 16:28:33 -05:00
payloads_manifest_errors = []
begin
payloads_manifest_errors = ::MetasploitPayloads.manifest_errors if framework.features.enabled?(::Msf::FeatureManager::METASPLOIT_PAYLOAD_WARNINGS)
rescue ::StandardError => e
$stderr.print('Could not verify the integrity of the Metasploit Payloads manifest')
elog(e)
end
2023-09-27 11:20:17 +01:00
av_warning_message if (framework.eicar_corrupted? || payloads_manifest_errors.any?)
if framework.features.enabled?(::Msf::FeatureManager::METASPLOIT_PAYLOAD_WARNINGS)
if payloads_manifest_errors.any?
warn_msg = "Metasploit Payloads manifest errors:\n"
payloads_manifest_errors.each do |file|
warn_msg << "\t#{file[:path]} : #{file[:error]}\n"
end
$stderr.print(warn_msg)
end
end
2020-12-09 14:47:22 +00:00
opts["Plugins"].each do |plug|
run_single("load '#{plug}'")
end if opts["Plugins"]
2013-08-30 16:28:33 -05:00
self.on_command_proc = Proc.new { |command| framework.events.on_ui_command(command) }
2005-05-22 19:39:21 +00:00
end
2013-08-30 16:28:33 -05:00
2020-12-09 14:47:22 +00:00
def av_warning_message
2020-12-10 17:24:30 +00:00
avdwarn = "\e[31m"\
"Warning: This copy of the Metasploit Framework has been corrupted by an installed anti-virus program."\
" We recommend that you disable your anti-virus or exclude your Metasploit installation path, "\
"then restore the removed files from quarantine or reinstall the framework.\e[0m"\
2020-12-14 15:20:15 +00:00
"\n\n"
2020-12-10 17:24:30 +00:00
$stderr.puts(Rex::Text.wordwrap(avdwarn, 0, 80))
2020-12-09 14:47:22 +00:00
end
2005-10-01 21:51:45 +00:00
#
# Called when a variable is set to a specific value. This allows the
# console to do extra processing, such as enabling logging or doing
# some other kind of task. If this routine returns false it will indicate
# that the variable is not being set to a valid value.
#
2005-10-02 03:21:26 +00:00
def on_variable_set(glob, var, val)
2005-10-01 21:51:45 +00:00
case var.downcase
2019-06-02 16:50:44 -05:00
when 'sessionlogging'
handle_session_logging(val) if glob
when 'sessiontlvlogging'
handle_session_tlv_logging(val) if glob
2019-06-02 16:50:44 -05:00
when 'consolelogging'
handle_console_logging(val) if glob
when 'loglevel'
handle_loglevel(val) if glob
when 'payload'
handle_payload(val)
2019-06-02 18:26:25 -05:00
when 'ssh_ident'
handle_ssh_ident(val)
2005-10-01 21:51:45 +00:00
end
end
2013-08-30 16:28:33 -05:00
2005-10-01 21:51:45 +00:00
#
# Called when a variable is unset. If this routine returns false it is an
# indication that the variable should not be allowed to be unset.
#
2005-10-02 03:21:26 +00:00
def on_variable_unset(glob, var)
case var.downcase
2019-06-02 16:55:48 -05:00
when 'sessionlogging'
handle_session_logging('0') if glob
when 'sessiontlvlogging'
handle_session_tlv_logging('false') if glob
2019-06-02 16:55:48 -05:00
when 'consolelogging'
handle_console_logging('0') if glob
when 'loglevel'
handle_loglevel(nil) if glob
2005-10-02 03:21:26 +00:00
end
2005-10-01 21:51:45 +00:00
end
2013-08-30 16:28:33 -05:00
#
# Proxies to shell.rb's update prompt with our own extras
#
def update_prompt(*args)
if args.empty?
pchar = framework.datastore['PromptChar'] || DefaultPromptChar
p = framework.datastore['Prompt'] || DefaultPrompt
2018-08-29 10:38:28 -05:00
p = "#{p} #{active_module.type}(%bld%red#{active_module.promptname}%clr)" if active_module
2018-08-17 14:32:48 -05:00
super(p, pchar)
else
# Don't squash calls from within lib/rex/ui/text/shell.rb
super(*args)
end
end
2005-11-15 15:11:43 +00:00
#
# The framework instance associated with this driver.
#
2005-07-18 05:13:21 +00:00
attr_reader :framework
#
# Whether or not to confirm before exiting
#
attr_reader :confirm_exit
2005-11-15 15:11:43 +00:00
#
2005-12-07 03:06:31 +00:00
# Whether or not commands can be passed through.
#
attr_reader :command_passthru
#
2005-11-15 15:11:43 +00:00
# The active module associated with the driver.
#
attr_accessor :active_module
#
# The active session associated with the driver.
#
attr_accessor :active_session
2013-08-30 16:28:33 -05:00
def stop
framework.events.on_ui_stop()
super
end
2005-05-22 19:39:21 +00:00
protected
2005-11-15 15:11:43 +00:00
attr_writer :framework # :nodoc:
attr_writer :confirm_exit # :nodoc:
2005-12-07 03:06:31 +00:00
attr_writer :command_passthru # :nodoc:
2013-08-30 16:28:33 -05:00
2005-12-07 03:06:31 +00:00
#
# If an unknown command was passed, try to see if it's a valid local
# executable. This is only allowed if command passthru has been permitted
#
def unknown_command(method, line)
2016-09-20 17:45:46 -05:00
if File.basename(method) == 'msfconsole'
2016-09-20 17:57:48 -05:00
print_error('msfconsole cannot be run inside msfconsole')
2016-09-20 17:45:46 -05:00
return
end
2013-08-30 16:28:33 -05:00
[method, method+".exe"].each do |cmd|
if command_passthru && Rex::FileUtils.find_full_path(cmd)
2013-08-30 16:28:33 -05:00
self.busy = true
begin
run_unknown_command(line)
rescue ::Errno::EACCES, ::Errno::ENOENT
print_error("Permission denied exec: #{line}")
end
self.busy = false
return
2020-03-06 23:32:09 +00:00
end
end
2020-03-06 23:32:09 +00:00
if framework.modules.create(method)
super
if prompt_yesno "This is a module we can load. Do you want to use #{method}?"
run_single "use #{method}"
2007-01-22 06:57:07 +00:00
end
2020-03-06 23:32:09 +00:00
return
2005-12-07 03:06:31 +00:00
end
2013-08-30 16:28:33 -05:00
super
2005-12-07 03:06:31 +00:00
end
2013-08-30 16:28:33 -05:00
def run_unknown_command(command)
2021-12-24 21:18:02 +11:00
print_status("exec: #{command}")
print_line('')
system(command)
end
2005-10-02 03:21:26 +00:00
##
#
# Handlers for various global configuration values
#
##
2013-08-30 16:28:33 -05:00
2005-10-02 03:21:26 +00:00
#
2005-11-15 15:11:43 +00:00
# SessionLogging.
2005-10-02 03:21:26 +00:00
#
def handle_session_logging(val)
2009-01-07 02:50:10 +00:00
if (val =~ /^(y|t|1)/i)
2005-10-02 03:21:26 +00:00
Msf::Logging.enable_session_logging(true)
print_line("Session logging will be enabled for future sessions.")
else
Msf::Logging.enable_session_logging(false)
print_line("Session logging will be disabled for future sessions.")
end
end
2013-08-30 16:28:33 -05:00
2005-10-02 04:05:17 +00:00
#
2005-11-15 15:11:43 +00:00
# ConsoleLogging.
2005-10-02 04:05:17 +00:00
#
def handle_console_logging(val)
2009-01-07 02:50:10 +00:00
if (val =~ /^(y|t|1)/i)
2005-10-02 04:05:17 +00:00
Msf::Logging.enable_log_source('console')
print_line("Console logging is now enabled.")
2013-08-30 16:28:33 -05:00
2005-10-02 04:05:17 +00:00
set_log_source('console')
2013-08-30 16:28:33 -05:00
2005-10-02 04:05:17 +00:00
rlog("\n[*] Console logging started: #{Time.now}\n\n", 'console')
else
rlog("\n[*] Console logging stopped: #{Time.now}\n\n", 'console')
2013-08-30 16:28:33 -05:00
2005-10-02 04:05:17 +00:00
unset_log_source
2013-08-30 16:28:33 -05:00
2005-10-02 04:05:17 +00:00
Msf::Logging.disable_log_source('console')
print_line("Console logging is now disabled.")
end
end
2013-08-30 16:28:33 -05:00
2005-10-30 23:40:27 +00:00
#
# This method handles adjusting the global log level threshold.
#
def handle_loglevel(val)
set_log_level(Rex::LogSource, val)
set_log_level(Msf::LogSource, val)
end
#
# This method handles setting a desired payload
#
# TODO: Move this out of the console driver!
#
def handle_payload(val)
if framework && !framework.payloads.valid?(val)
return false
elsif active_module && (active_module.exploit? || active_module.evasion?)
return false unless active_module.is_payload_compatible?(val)
elsif active_module && !framework.features.enabled?(Msf::FeatureManager::DATASTORE_FALLBACKS)
active_module.datastore.clear_non_user_defined
elsif framework && !framework.features.enabled?(Msf::FeatureManager::DATASTORE_FALLBACKS)
framework.datastore.clear_non_user_defined
end
end
#
2019-06-02 17:04:31 -05:00
# This method monkeypatches Net::SSH's client identification string
#
# TODO: Move this out of the console driver!
#
2019-06-02 18:26:25 -05:00
def handle_ssh_ident(val)
2019-06-06 12:33:54 -05:00
# HACK: Suppress already initialized constant warning
verbose, $VERBOSE = $VERBOSE, nil
2019-06-02 16:53:02 -05:00
return false unless val.is_a?(String) && !val.empty?
2019-06-03 03:51:08 -05:00
require 'net/ssh'
2019-06-03 03:51:08 -05:00
# HACK: Bypass dynamic constant assignment error
::Net::SSH::Transport::ServerVersion.const_set(:PROTO_VERSION, val)
true
2019-06-03 03:51:08 -05:00
rescue LoadError
print_error('Net::SSH could not be loaded')
false
rescue NameError
print_error('Invalid constant Net::SSH::Transport::ServerVersion::PROTO_VERSION')
false
ensure
2019-06-06 10:50:26 -05:00
# Restore warning
2019-06-03 03:51:08 -05:00
$VERBOSE = verbose
end
def handle_session_tlv_logging(val)
return false if val.nil?
if val.casecmp?('console') || val.casecmp?('true') || val.casecmp?('false')
return true
elsif val.start_with?('file:') && !val.split('file:').empty?
pathname = ::Pathname.new(val.split('file:').last)
# Check if we want to write the log to file
if ::File.file?(pathname)
if ::File.writable?(pathname)
return true
else
print_status "No write permissions for log output file: #{pathname}"
return false
end
# Check if we want to write the log file to a directory
elsif ::File.directory?(pathname)
if ::File.writable?(pathname)
return true
else
print_status "No write permissions for log output directory: #{pathname}"
return false
end
# Check if the subdirectory exists
elsif ::File.directory?(pathname.dirname)
if ::File.writable?(pathname.dirname)
return true
else
print_status "No write permissions for log output directory: #{pathname.dirname}"
return false
end
else
# Else the directory doesn't exist. Check if we can create it.
begin
::FileUtils.mkdir_p(pathname.dirname)
return true
rescue ::StandardError => e
print_status "Error when trying to create directory #{pathname.dirname}: #{e.message}"
return false
end
end
end
false
end
2014-10-29 22:33:23 -05:00
# Require the appropriate readline library based on the user's preference.
#
# @return [void]
def choose_readline(opts)
# Choose a readline library before calling the parent
@rl_err = nil
if opts['RealReadline']
# Remove the gem version from load path to be sure we're getting the
# stdlib readline.
gem_dir = Gem::Specification.find_all_by_name('rb-readline').first.gem_dir
2014-10-29 22:33:23 -05:00
rb_readline_path = File.join(gem_dir, "lib")
index = $LOAD_PATH.index(rb_readline_path)
# Bundler guarantees that the gem will be there, so it should be safe to
# assume we found it in the load path, but check to be on the safe side.
if index
$LOAD_PATH.delete_at(index)
end
end
begin
require 'readline'
rescue ::LoadError => e
if @rl_err.nil? && index
# Then this is the first time the require failed and we have an index
# for the gem version as a fallback.
@rl_err = e
# Put the gem back and see if that works
$LOAD_PATH.insert(index, rb_readline_path)
index = rb_readline_path = nil
retry
else
# Either we didn't have the gem to fall back on, or we failed twice.
# Nothing more we can do here.
raise e
end
end
end
2005-05-22 19:39:21 +00:00
end
end
end
2018-08-21 03:05:44 +00:00
end