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, #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) ⇒ 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, #reset_ui, #run, #set_log_source, #stop, #stopped?, #unset_log_source, #update_prompt
Instance Attribute Details
#blocked ⇒ Object
:nodoc:
461 462 463 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 461 def blocked @blocked end |
#busy ⇒ Object
:nodoc:
460 461 462 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 460 def busy @busy end |
#dispatcher_stack ⇒ Object
:nodoc:
458 459 460 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 458 def dispatcher_stack @dispatcher_stack end |
#tab_words ⇒ Object
:nodoc:
459 460 461 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 459 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.
363 364 365 366 367 368 369 370 371 372 373 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 363 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
444 445 446 447 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 444 def block_command(cmd) self.blocked ||= {} self.blocked[cmd] = true end |
#blocked_command?(cmd) ⇒ Boolean
Returns nil for an empty set of blocked commands.
436 437 438 439 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 436 def blocked_command?(cmd) return false if not self.blocked self.blocked.has_key?(cmd) end |
#current_dispatcher ⇒ Object
Returns the current active dispatcher
387 388 389 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 387 def current_dispatcher self.dispatcher_stack[0] end |
#destack_dispatcher ⇒ Object
Pop a dispatcher from the front of the stacker.
355 356 357 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 355 def destack_dispatcher self.dispatcher_stack.shift end |
#enstack_dispatcher(dispatcher) ⇒ Object
Push a dispatcher to the front of the stack.
346 347 348 349 350 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 346 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.
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 395 def help_to_s(opts = {}) str = '' dispatcher_stack.reverse.each { |dispatcher| # No commands? Suckage. next if ((dispatcher.respond_to?('commands') == false) or (dispatcher.commands == nil) or (dispatcher.commands.length == 0)) # Display the commands tbl = Table.new( 'Header' => "#{dispatcher.name} Commands", 'Indent' => opts['Indent'] || 4, 'Columns' => [ 'Command', 'Description' ], 'ColProps' => { 'Command' => { 'MaxWidth' => 12 } }) dispatcher.commands.sort.each { |c| tbl << c } str << "\n" + tbl.to_s + "\n" } return str end |
#initialize(prompt, prompt_char = '>', histfile = nil) ⇒ Object
Initialize the dispatcher shell.
162 163 164 165 166 167 168 169 170 171 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 162 def initialize(prompt, prompt_char = '>', histfile = 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.
378 379 380 381 382 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 378 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.
325 326 327 328 329 330 331 332 333 334 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 325 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.
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 275 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)) 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
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 180 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
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 255 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
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 201 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 # XXX - 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 gets replaced!) }.map { |e| tab_words.dup.push(e).join(' ') } end |
#unblock_command(cmd) ⇒ Object
Unblock a specific command
452 453 454 455 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 452 def unblock_command(cmd) self.blocked || return self.blocked.delete(cmd) end |
#unknown_command(method, line) ⇒ Object
If the command is unknown…
339 340 341 |
# File 'lib/rex/ui/text/dispatcher_shell.rb', line 339 def unknown_command(method, line) print_error("Unknown command: #{method}.") end |