@@ -53,6 +53,8 @@ class Driver < Msf::Ui::Driver
5353 # @option opts [Boolean] 'AllowCommandPassthru' (true) Whether to allow
5454 # unrecognized commands to be executed by the system shell
5555 # @option opts [Boolean] 'Readline' (true) Whether to use the readline or not
56+ # @option opts [Boolean] 'RealReadline' (false) Whether to use the system's
57+ # readline library instead of RBReadline
5658 # @option opts [String] 'HistFile' (Msf::Config.history_file) Path to a file
5759 # where we can store command history
5860 # @option opts [Array<String>] 'Resources' ([]) A list of resource files to
@@ -62,6 +64,8 @@ class Driver < Msf::Ui::Driver
6264 # @option opts [Boolean] 'SkipDatabaseInit' (false) Whether to skip
6365 # connecting to the database and running migrations
6466 def initialize ( prompt = DefaultPrompt , prompt_char = DefaultPromptChar , opts = { } )
67+ choose_readline ( opts )
68+
6569 histfile = opts [ 'HistFile' ] || Msf ::Config . history_file
6670
6771 begin
@@ -128,6 +132,14 @@ def initialize(prompt = DefaultPrompt, prompt_char = DefaultPromptChar, opts = {
128132 # stack
129133 enstack_dispatcher ( CommandDispatcher ::Core )
130134
135+ # Report readline error if there was one..
136+ if !@rl_err . nil?
137+ print_error ( "***" )
138+ print_error ( "* Unable to load readline: #{ @rl_err } " )
139+ print_error ( "* Falling back to RbReadLine" )
140+ print_error ( "***" )
141+ end
142+
131143 # Load the other "core" command dispatchers
132144 CommandDispatchers . each do |dispatcher_class |
133145 dispatcher = enstack_dispatcher ( dispatcher_class )
@@ -311,11 +323,11 @@ def save_config
311323 # Saves the recent history to the specified file
312324 #
313325 def save_recent_history ( path )
314- num = :: Reline ::HISTORY . length - hist_last_saved - 1
326+ num = Readline ::HISTORY . length - hist_last_saved - 1
315327
316328 tmprc = ""
317329 num . times { |x |
318- tmprc << :: Reline ::HISTORY [ hist_last_saved + x ] + "\n "
330+ tmprc << Readline ::HISTORY [ hist_last_saved + x ] + "\n "
319331 }
320332
321333 if tmprc . length > 0
@@ -327,7 +339,7 @@ def save_recent_history(path)
327339
328340 # Always update this, even if we didn't save anything. We do this
329341 # so that we don't end up saving the "makerc" command itself.
330- self . hist_last_saved = :: Reline ::HISTORY . length
342+ self . hist_last_saved = Readline ::HISTORY . length
331343 end
332344
333345 #
@@ -690,6 +702,44 @@ def handle_session_tlv_logging(val)
690702
691703 false
692704 end
705+
706+ # Require the appropriate readline library based on the user's preference.
707+ #
708+ # @return [void]
709+ def choose_readline ( opts )
710+ # Choose a readline library before calling the parent
711+ @rl_err = nil
712+ if opts [ 'RealReadline' ]
713+ # Remove the gem version from load path to be sure we're getting the
714+ # stdlib readline.
715+ gem_dir = Gem ::Specification . find_all_by_name ( 'rb-readline' ) . first . gem_dir
716+ rb_readline_path = File . join ( gem_dir , "lib" )
717+ index = $LOAD_PATH. index ( rb_readline_path )
718+ # Bundler guarantees that the gem will be there, so it should be safe to
719+ # assume we found it in the load path, but check to be on the safe side.
720+ if index
721+ $LOAD_PATH. delete_at ( index )
722+ end
723+ end
724+
725+ begin
726+ require 'readline'
727+ rescue ::LoadError => e
728+ if @rl_err . nil? && index
729+ # Then this is the first time the require failed and we have an index
730+ # for the gem version as a fallback.
731+ @rl_err = e
732+ # Put the gem back and see if that works
733+ $LOAD_PATH. insert ( index , rb_readline_path )
734+ index = rb_readline_path = nil
735+ retry
736+ else
737+ # Either we didn't have the gem to fall back on, or we failed twice.
738+ # Nothing more we can do here.
739+ raise e
740+ end
741+ end
742+ end
693743end
694744
695745end
0 commit comments