From d5978803eba98119b44f476fd8102f67f6709f3c Mon Sep 17 00:00:00 2001 From: christopher lee Date: Fri, 19 Jan 2018 15:16:19 -0600 Subject: [PATCH 1/2] Fix all failing rspec for goliath --- .../framework/data_service/proxy/core.rb | 80 +++++++------------ lib/msf/core/db_manager/connection.rb | 2 +- lib/msf/core/db_manager/host.rb | 2 +- lib/msf/core/db_manager/workspace.rb | 14 ++-- lib/msf/core/framework.rb | 15 +++- lib/msf/core/modules/metadata/store.rb | 2 +- .../ui/console/command_dispatcher/creds.rb | 1 - lib/msf/ui/console/command_dispatcher/db.rb | 18 ++++- lib/msf/ui/console/driver.rb | 1 - spec/lib/msf/core/auxiliary/cisco_spec.rb | 2 +- .../support/shared/contexts/msf/db_manager.rb | 4 +- .../shared/examples/msf/db_manager/host.rb | 1 - .../shared/examples/msf/db_manager/session.rb | 28 ------- 13 files changed, 75 insertions(+), 95 deletions(-) diff --git a/lib/metasploit/framework/data_service/proxy/core.rb b/lib/metasploit/framework/data_service/proxy/core.rb index bda98e6f4a..84ccacae60 100644 --- a/lib/metasploit/framework/data_service/proxy/core.rb +++ b/lib/metasploit/framework/data_service/proxy/core.rb @@ -1,8 +1,6 @@ -require 'singleton' require 'open3' require 'rex/ui' require 'rex/logging' -require 'msf/core/db_manager' require 'metasploit/framework/data_service/remote/http/core' require 'metasploit/framework/data_service/remote/http/remote_service_endpoint' require 'metasploit/framework/data_service/proxy/data_proxy_auto_loader' @@ -15,11 +13,17 @@ module Metasploit module Framework module DataService class DataProxy - include Singleton include DataProxyAutoLoader attr_reader :usable + def initialize(opts = {}) + @data_services = {} + @data_service_id = 0 + @usable = false + setup(opts) + end + # # Returns current error state # @@ -48,34 +52,6 @@ class DataProxy return false end - # - # Initializes the data service to be used - primarily on startup - # - def init(framework, opts) - @mutex.synchronize { - if (@initialized) - return - end - - begin - if (opts['DisableDatabase']) - @error = 'disabled' - return - elsif (opts['DatabaseRemoteProcess']) - run_remote_db_process(opts) - else - run_local_db_process(framework, opts) - end - @usable = true - @initialized = true - rescue Exception => e - puts "Unable to initialize a dataservice #{e.message}" - return - end - } - - end - # # Registers a data service with the proxy and immediately # set as primary if online @@ -131,6 +107,14 @@ class DataProxy end end + def respond_to?(method_name, include_private=false) + unless @data_service.nil? + return @data_service.respond_to?(method_name, include_private) + end + + false + end + # # Attempt to shutdown the local db process if it exists # @@ -145,10 +129,6 @@ class DataProxy end end - ######### - protected - ######### - def get_data_service raise 'No registered data_service' unless @data_service return @data_service @@ -158,12 +138,21 @@ class DataProxy private ####### - def initialize - @data_services = {} - @data_service_id = 0 - @usable = false - @initialized = false - @mutex = Mutex.new() + def setup(opts) + begin + db_manager = opts.delete(:db_manager) + if !db_manager.nil? + register_data_service(db_manager, true) + @usable = true + elsif (opts['DatabaseRemoteProcess']) + run_remote_db_process(opts) + @usable = true + else + @error = 'disabled' + end + rescue Exception => e + puts "Unable to initialize a dataservice #{e.message}" + end end def validate(data_service) @@ -183,15 +172,6 @@ class DataProxy end - def run_local_db_process(framework, opts) - puts 'Initializing local db process' - db_manager = Msf::DBManager.new(framework) - if (db_manager.usable and not opts['SkipDatabaseInit']) - register_data_service(db_manager, true) - db_manager.init_db(opts) - end - end - def run_remote_db_process(opts) # started with no signal to prevent ctrl-c from taking out db db_script = File.join( Msf::Config.install_root, "msfdb -ns") diff --git a/lib/msf/core/db_manager/connection.rb b/lib/msf/core/db_manager/connection.rb index 5f47998b50..70e7889c73 100644 --- a/lib/msf/core/db_manager/connection.rb +++ b/lib/msf/core/db_manager/connection.rb @@ -18,7 +18,7 @@ module Msf::DBManager::Connection migrate # Set the default workspace - framework.db.workspace = framework.db.default_workspace + self.workspace = self.default_workspace rescue ::Exception => exception self.error = exception elog("DB.connect threw an exception: #{exception}") diff --git a/lib/msf/core/db_manager/host.rb b/lib/msf/core/db_manager/host.rb index 8789d7cbe2..9cdeb41b7e 100644 --- a/lib/msf/core/db_manager/host.rb +++ b/lib/msf/core/db_manager/host.rb @@ -56,7 +56,7 @@ module Msf::DBManager::Host # Exactly like report_host but waits for the database to create a host and returns it. def find_or_create_host(opts) - host = get_host(opts) + host = get_host(opts.clone) return host unless host.nil? report_host(opts) diff --git a/lib/msf/core/db_manager/workspace.rb b/lib/msf/core/db_manager/workspace.rb index b808e9869d..e1f45d0fd2 100644 --- a/lib/msf/core/db_manager/workspace.rb +++ b/lib/msf/core/db_manager/workspace.rb @@ -58,20 +58,23 @@ module Msf::DBManager::Workspace end def delete_all_workspaces() - delete_workspaces(workspaces.map(&:name)) + return delete_workspaces(workspaces.map(&:name)) end def delete_workspaces(names) + status_msg = [] + error_msg = [] + switched = false # Delete workspaces names.each do |name| workspace = framework.db.find_workspace(name) if workspace.nil? - print_error("Workspace not found: #{name}") + error << "Workspace not found: #{name}" elsif workspace.default? workspace.destroy workspace = framework.db.add_workspace(name) - print_status("Deleted and recreated the default workspace") + status_msg << 'Deleted and recreated the default workspace' else # switch to the default workspace if we're about to delete the current one if framework.db.workspace.name == workspace.name @@ -80,10 +83,11 @@ module Msf::DBManager::Workspace end # now destroy the named workspace workspace.destroy - print_status("Deleted workspace: #{name}") + status_msg << "Deleted workspace: #{name}" end end - print_status("Switched workspace: #{framework.db.workspace.name}") if switched + (status_msg << "Switched workspace: #{framework.db.workspace.name}") if switched + return status_msg, error_msg end # diff --git a/lib/msf/core/framework.rb b/lib/msf/core/framework.rb index 0bf08276fb..693862e329 100644 --- a/lib/msf/core/framework.rb +++ b/lib/msf/core/framework.rb @@ -199,7 +199,7 @@ class Framework # @return [Metasploit::Framework::DataService::DataProxy] def db synchronize { - @db ||= Metasploit::Framework::DataService::DataProxy.instance + @db ||= get_db } end @@ -268,6 +268,19 @@ protected attr_writer :db # :nodoc: attr_writer :uuid_db # :nodoc: attr_writer :browser_profiles # :nodoc: + + private + + def get_db + if !options['DatabaseRemoteProcess'] && !options['DisableDatabase'] + db_manager = Msf::DBManager.new(self) + db_manager.init_db(options) + options[:db_manager] = db_manager + end + + Metasploit::Framework::DataService::DataProxy.new(options) + end + end class FrameworkEventSubscriber diff --git a/lib/msf/core/modules/metadata/store.rb b/lib/msf/core/modules/metadata/store.rb index 3a10a7c8c0..d2a720e0af 100644 --- a/lib/msf/core/modules/metadata/store.rb +++ b/lib/msf/core/modules/metadata/store.rb @@ -104,7 +104,7 @@ module Msf::Modules::Metadata::Store def get_user_store store_dir = ::File.join(Msf::Config.config_directory, "store") - FileUtils.mkdir(store_dir) if !::File.exist?(store_dir) + FileUtils.makedirs(store_dir) if !::File.exist?(store_dir) return ::File.join(store_dir, UserMetaDataFile) end diff --git a/lib/msf/ui/console/command_dispatcher/creds.rb b/lib/msf/ui/console/command_dispatcher/creds.rb index c21e46209d..b5abdb830f 100644 --- a/lib/msf/ui/console/command_dispatcher/creds.rb +++ b/lib/msf/ui/console/command_dispatcher/creds.rb @@ -393,7 +393,6 @@ class Creds } tbl = Rex::Text::Table.new(tbl_opts) - opts = {} opts[:wspace] = framework.db.workspace query = framework.db.creds(opts) diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index 668a241d9c..59346a76e6 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -256,9 +256,11 @@ module Msf end framework.db.workspace = workspace elsif deleting and names - framework.db.delete_workspaces(names) + status_msg, error_msg = framework.db.delete_workspaces(names) + print_msgs(status_msg, error_msg) elsif delete_all - framework.db.delete_all_workspaces() + status_msg, error_msg = framework.db.delete_all_workspaces() + print_msgs(status_msg, error_msg) elsif renaming if names.length != 2 print_error("Wrong number of arguments to rename") @@ -1993,6 +1995,18 @@ module Msf end end + private + + def print_msgs(status_msg, error_msg) + status_msg.each do |s| + print_status(s) + end + + error_msg.each do |e| + print_error(e) + end + end + end end end end end diff --git a/lib/msf/ui/console/driver.rb b/lib/msf/ui/console/driver.rb index 829551cf1b..72e10a2b3c 100644 --- a/lib/msf/ui/console/driver.rb +++ b/lib/msf/ui/console/driver.rb @@ -122,7 +122,6 @@ class Driver < Msf::Ui::Driver enstack_dispatcher(dispatcher) end - framework.db.init(framework, opts) if (framework.db.active) require 'msf/ui/console/command_dispatcher/db' enstack_dispatcher(CommandDispatcher::Db) diff --git a/spec/lib/msf/core/auxiliary/cisco_spec.rb b/spec/lib/msf/core/auxiliary/cisco_spec.rb index f9adb0a9d2..c481318da4 100644 --- a/spec/lib/msf/core/auxiliary/cisco_spec.rb +++ b/spec/lib/msf/core/auxiliary/cisco_spec.rb @@ -77,7 +77,7 @@ RSpec.describe Msf::Auxiliary::Cisco do context '#cisco_ios_config_eater' do before(:example) do - expect(aux_cisco).to receive(:myworkspace).and_return(workspace) + expect(aux_cisco).to receive(:myworkspace).at_least(:once).and_return(workspace) end it 'deals with udp ports' do diff --git a/spec/support/shared/contexts/msf/db_manager.rb b/spec/support/shared/contexts/msf/db_manager.rb index 482c939dcd..f6c94dd73c 100644 --- a/spec/support/shared/contexts/msf/db_manager.rb +++ b/spec/support/shared/contexts/msf/db_manager.rb @@ -6,12 +6,12 @@ RSpec.shared_context 'Msf::DBManager' do end let(:db_manager) do - framework.db + framework.db.get_data_service end before(:example) do # already connected due to use_transactional_fixtures, but need some of the side-effects of #connect - framework.db.workspace = framework.db.default_workspace + db_manager.workspace = db_manager.default_workspace allow(db_manager).to receive(:active).and_return(active) end end diff --git a/spec/support/shared/examples/msf/db_manager/host.rb b/spec/support/shared/examples/msf/db_manager/host.rb index 43abeca732..d92e0b4b0c 100644 --- a/spec/support/shared/examples/msf/db_manager/host.rb +++ b/spec/support/shared/examples/msf/db_manager/host.rb @@ -5,7 +5,6 @@ RSpec.shared_examples_for 'Msf::DBManager::Host' do it { is_expected.to respond_to :get_host } it { is_expected.to respond_to :has_host? } it { is_expected.to respond_to :hosts } - it { is_expected.to respond_to :normalize_host } it { is_expected.to respond_to :report_host } it { is_expected.to respond_to :update_host_via_sysinfo } end \ No newline at end of file diff --git a/spec/support/shared/examples/msf/db_manager/session.rb b/spec/support/shared/examples/msf/db_manager/session.rb index 80c67cf116..934cbc3777 100644 --- a/spec/support/shared/examples/msf/db_manager/session.rb +++ b/spec/support/shared/examples/msf/db_manager/session.rb @@ -172,20 +172,6 @@ RSpec.shared_examples_for 'Msf::DBManager::Session' do end context 'with workspace from either :workspace or session' do - it 'should pass normalized host from session as :host to #find_or_create_host' do - normalized_host = double('Normalized Host') - expect(db_manager).to receive(:normalize_host).with(session).and_return(normalized_host) - # stub report_vuln so its use of find_or_create_host and Msf::Util::Host.normalize_host doesn't interfere. - expect(db_manager).to receive(:report_vuln) - - expect(db_manager).to receive(:find_or_create_host).with( - hash_including( - :host => normalized_host - ) - ).and_return(host) - - report_session - end context 'with session responds to arch' do let(:arch) do @@ -515,20 +501,6 @@ RSpec.shared_examples_for 'Msf::DBManager::Session' do end context 'with workspace from either :workspace or session' do - it 'should pass normalized host from session as :host to #find_or_create_host' do - normalized_host = double('Normalized Host') - allow(db_manager).to receive(:normalize_host).with(session).and_return(normalized_host) - # stub report_vuln so its use of find_or_create_host and Msf::Util::Host.normalize_host doesn't interfere. - allow(db_manager).to receive(:report_vuln) - - expect(db_manager).to receive(:find_or_create_host).with( - hash_including( - :host => normalized_host - ) - ).and_return(host) - - report_session - end context 'with session responds to arch' do let(:arch) do From 2521c941d4d4ef4726a1b48c1e9e55e0ded0e4a7 Mon Sep 17 00:00:00 2001 From: christopher lee Date: Mon, 22 Jan 2018 14:57:28 -0600 Subject: [PATCH 2/2] Ported singleton calls --- .../framework/data_service/proxy/core.rb | 2 +- lib/msf/ui/console/command_dispatcher/db.rb | 18 ++++++------------ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/lib/metasploit/framework/data_service/proxy/core.rb b/lib/metasploit/framework/data_service/proxy/core.rb index 84ccacae60..a9315d3176 100644 --- a/lib/metasploit/framework/data_service/proxy/core.rb +++ b/lib/metasploit/framework/data_service/proxy/core.rb @@ -144,7 +144,7 @@ class DataProxy if !db_manager.nil? register_data_service(db_manager, true) @usable = true - elsif (opts['DatabaseRemoteProcess']) + elsif opts['DatabaseRemoteProcess'] run_remote_db_process(opts) @usable = true else diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index 59346a76e6..530dcdd887 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -90,13 +90,11 @@ module Msf end def cmd_set_data_service(service_id) - data_proxy = Metasploit::Framework::DataService::DataProxy.instance - data_proxy.set_data_service(service_id) + framework.db.set_data_service(service_id) end def cmd_list_data_services() - data_service_manager = Metasploit::Framework::DataService::DataProxy.instance - data_service_manager.print_data_services + framework.db.print_data_services end def cmd_add_data_service(*args) @@ -111,8 +109,7 @@ module Msf remote_service_endpoint = Metasploit::Framework::DataService::RemoteServiceEndpoint.new(host, port) remote_data_service = Metasploit::Framework::DataService::RemoteHTTPDataService.new(remote_service_endpoint) - data_service_manager = Metasploit::Framework::DataService::DataProxy.instance - data_service_manager.register_data_service(remote_data_service) + framework.db.register_data_service(remote_data_service) end def cmd_test_data_service_host(*args) @@ -129,8 +126,7 @@ module Msf end puts 'Reporting test host to data service' - data_service = Metasploit::Framework::DataService::DataProxy.instance - data_service.report_host host + framework.db.report_host host end def cmd_test_data_service_loot(*args) @@ -153,8 +149,7 @@ module Msf end puts 'Reporting test loot to data service' - data_service = Metasploit::Framework::DataService::DataProxy.instance - data_service.report_loot loot + framework.db.report_loot loot end def cmd_perf_test_data_service_loot(*args) @@ -198,11 +193,10 @@ module Msf end puts 'Reporting test loot to data service' - data_service = Metasploit::Framework::DataService::DataProxy.instance start_time = Time.now puts "#{start_time} - Staring loot perf test" loots.each do |loot| - data_service.report_loot loot + framework.db.report_loot loot end end_time = Time.now puts "#{end_time} - Ending loot perf test. Duration was #{end_time - start_time}"