Module: Rex::Ui::Text::DispatcherShell
- Includes:
- Shell
- Included in:
- Post::Meterpreter::Ui::Console
- Defined in:
- lib/rex/ui/text/dispatcher_shell.rb
Overview
The dispatcher shell class is designed to provide a generic means of processing various shell commands that may be located in different modules or chunks of codes. These chunks are referred to as command dispatchers. The only requirement for command dispatchers is that they prefix every method that they wish to be mirrored as a command with the cmd_ prefix.
Defined Under Namespace
Modules: CommandDispatcher
Instance Attribute Summary collapse
-
#blocked ⇒ Object
:nodoc:.
-
#busy ⇒ Object
:nodoc:.
-
#dispatcher_stack ⇒ Object
:nodoc:.
-
#tab_words ⇒ Object
:nodoc:.
Attributes included from Shell
#disable_output, #framework, #input, #on_command_proc, #on_print_proc, #output
Instance Method Summary collapse
-
#append_dispatcher(dispatcher) ⇒ Object
Adds the supplied dispatcher to the end of the dispatcher stack so that it doesn’t affect any enstack’d dispatchers.
-
#block_command(cmd) ⇒ Object
Block a specific command.
-
#blocked_command?(cmd) ⇒ Boolean
Returns nil for an empty set of blocked commands.
-
#current_dispatcher ⇒ Object
Returns the current active dispatcher.
-
#destack_dispatcher ⇒ Object
Pop a dispatcher from the front of the stacker.
-
#enstack_dispatcher(dispatcher) ⇒ Object
Push a dispatcher to the front of the stack.
-
#help_to_s(opts = {}) ⇒ Object
Return a readable version of a help banner for all of the enstacked dispatchers.
-
#initialize(prompt, prompt_char = '>', histfile = nil, framework = nil) ⇒ Object
Initialize the dispatcher shell.
-
#remove_dispatcher(name) ⇒ Object
Removes the supplied dispatcher instance.
-
#run_command(dispatcher, method, arguments) ⇒ Object
Runs the supplied command on the given dispatcher.
-
#run_single(line) ⇒ Object
Run a single command line.
-
#tab_complete(str) ⇒ Object
This method accepts the entire line of text from the Readline routine, stores all completed words, and passes the partial word to the real tab completion function.
-
#tab_complete_helper(dispatcher, str, words) ⇒ Object
Provide command-specific tab completion.
-
#tab_complete_stub(str) ⇒ Object
Performs tab completion of a command, if supported Current words can be found in self.tab_words.
-
#unblock_command(cmd) ⇒ Object
Unblock a specific command.
-
#unknown_command(method, line) ⇒ Object
If the command is unknown…
Methods included from Shell
#init_tab_complete, #init_ui, #print, #print_error, #print_good, #print_line, #print_status, #print_warning, #reset_ui, #run, #set_log_source, #stop, #stopped?, #unset_log_source, #update_prompt
Instance Attribute Details
#blocked ⇒ Object
:nodoc:
532 533 534 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 532 def blocked @blocked end |
#busy ⇒ Object
:nodoc:
531 532 533 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 531 def busy @busy end |
#dispatcher_stack ⇒ Object
:nodoc:
529 530 531 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 529 def dispatcher_stack @dispatcher_stack end |
#tab_words ⇒ Object
:nodoc:
530 531 532 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 530 def tab_words @tab_words end |
Instance Method Details
#append_dispatcher(dispatcher) ⇒ Object
Adds the supplied dispatcher to the end of the dispatcher stack so that it doesn’t affect any enstack’d dispatchers.
459 460 461 462 463 464 465 466 467 468 469 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 459 def append_dispatcher(dispatcher) inst = dispatcher.new(self) self.dispatcher_stack.each { |disp| if (disp.name == inst.name) raise RuntimeError.new("Attempting to load already loaded dispatcher #{disp.name}") end } self.dispatcher_stack.push(inst) inst end |
#block_command(cmd) ⇒ Object
Block a specific command
515 516 517 518 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 515 def block_command(cmd) self.blocked ||= {} self.blocked[cmd] = true end |
#blocked_command?(cmd) ⇒ Boolean
Returns nil for an empty set of blocked commands.
507 508 509 510 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 507 def blocked_command?(cmd) return false if not self.blocked self.blocked.has_key?(cmd) end |
#current_dispatcher ⇒ Object
Returns the current active dispatcher
483 484 485 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 483 def current_dispatcher self.dispatcher_stack[0] end |
#destack_dispatcher ⇒ Object
Pop a dispatcher from the front of the stacker.
451 452 453 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 451 def destack_dispatcher self.dispatcher_stack.shift end |
#enstack_dispatcher(dispatcher) ⇒ Object
Push a dispatcher to the front of the stack.
442 443 444 445 446 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 442 def enstack_dispatcher(dispatcher) self.dispatcher_stack.unshift(inst = dispatcher.new(self)) inst end |
#help_to_s(opts = {}) ⇒ Object
Return a readable version of a help banner for all of the enstacked dispatchers.
See CommandDispatcher#help_to_s
493 494 495 496 497 498 499 500 501 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 493 def help_to_s(opts = {}) str = '' dispatcher_stack.reverse.each { |dispatcher| str << dispatcher.help_to_s } return str end |
#initialize(prompt, prompt_char = '>', histfile = nil, framework = nil) ⇒ Object
Initialize the dispatcher shell.
258 259 260 261 262 263 264 265 266 267 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 258 def initialize(prompt, prompt_char = '>', histfile = nil, framework = nil) super # Initialze the dispatcher array self.dispatcher_stack = [] # Initialize the tab completion array self.tab_words = [] self.on_command_proc = nil end |
#remove_dispatcher(name) ⇒ Object
Removes the supplied dispatcher instance.
474 475 476 477 478 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 474 def remove_dispatcher(name) self.dispatcher_stack.delete_if { |inst| (inst.name == name) } end |
#run_command(dispatcher, method, arguments) ⇒ Object
Runs the supplied command on the given dispatcher.
421 422 423 424 425 426 427 428 429 430 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 421 def run_command(dispatcher, method, arguments) self.busy = true if(blocked_command?(method)) print_error("The #{method} command has been disabled.") else dispatcher.send('cmd_' + method, *arguments) end self.busy = false end |
#run_single(line) ⇒ Object
Run a single command line.
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 371 def run_single(line) arguments = parse_line(line) method = arguments.shift found = false error = false # If output is disabled output will be nil output.reset_color if (output) if (method) entries = dispatcher_stack.length dispatcher_stack.each { |dispatcher| next if not dispatcher.respond_to?('commands') begin if (dispatcher.commands.has_key?(method) or dispatcher.deprecated_commands.include?(method)) self.on_command_proc.call(line.strip) if self.on_command_proc run_command(dispatcher, method, arguments) found = true end rescue error = $! print_error( "Error while running command #{method}: #{$!}" + "\n\nCall stack:\n#{$@.join("\n")}") rescue ::Exception error = $! print_error( "Error while running command #{method}: #{$!}") end # If the dispatcher stack changed as a result of this command, # break out break if (dispatcher_stack.length != entries) } if (found == false and error == false) unknown_command(method, line) end end return found end |
#tab_complete(str) ⇒ Object
This method accepts the entire line of text from the Readline routine, stores all completed words, and passes the partial word to the real tab completion function. This works around a design problem in the Readline module and depends on the Readline.basic_word_break_characters variable being set to x00
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 276 def tab_complete(str) # Check trailing whitespace so we can tell 'x' from 'x ' str_match = str.match(/\s+$/) str_trail = (str_match.nil?) ? '' : str_match[0] # Split the line up by whitespace into words str_words = str.split(/[\s\t\n]+/) # Append an empty word if we had trailing whitespace str_words << '' if str_trail.length > 0 # Place the word list into an instance variable self.tab_words = str_words # Pop the last word and pass it to the real method tab_complete_stub(self.tab_words.pop) end |
#tab_complete_helper(dispatcher, str, words) ⇒ Object
Provide command-specific tab completion
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 351 def tab_complete_helper(dispatcher, str, words) items = [] tabs_meth = "cmd_#{words[0]}_tabs" # Is the user trying to tab complete one of our commands? if (dispatcher.commands.include?(words[0]) and dispatcher.respond_to?(tabs_meth)) res = dispatcher.send(tabs_meth, str, words) return [] if res.nil? items.concat(res) else # Avoid the default completion list for known commands return [] end return items end |
#tab_complete_stub(str) ⇒ Object
Performs tab completion of a command, if supported Current words can be found in self.tab_words
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 297 def tab_complete_stub(str) items = [] return nil if not str # puts "Words(#{tab_words.join(", ")}) Partial='#{str}'" # Next, try to match internal command or value completion # Enumerate each entry in the dispatcher stack dispatcher_stack.each { |dispatcher| # If no command is set and it supports commands, add them all if (tab_words.empty? and dispatcher.respond_to?('commands')) items.concat(dispatcher.commands.keys) end # If the dispatcher exports a tab completion function, use it if(dispatcher.respond_to?('tab_complete_helper')) res = dispatcher.tab_complete_helper(str, tab_words) else res = tab_complete_helper(dispatcher, str, tab_words) end if (res.nil?) # A nil response indicates no optional arguments return [''] if items.empty? else # Otherwise we add the completion items to the list items.concat(res) end } # Verify that our search string is a valid regex begin Regexp.compile(str) rescue RegexpError str = Regexp.escape(str) end # @todo - This still doesn't fix some Regexp warnings: # ./lib/rex/ui/text/dispatcher_shell.rb:171: warning: regexp has `]' without escape # Match based on the partial word items.find_all { |e| e =~ /^#{str}/ # Prepend the rest of the command (or it all gets replaced!) }.map { |e| tab_words.dup.push(e).join(' ') } end |
#unblock_command(cmd) ⇒ Object
Unblock a specific command
523 524 525 526 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 523 def unblock_command(cmd) self.blocked || return self.blocked.delete(cmd) end |
#unknown_command(method, line) ⇒ Object
If the command is unknown…
435 436 437 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 435 def unknown_command(method, line) print_error("Unknown command: #{method}.") end |