Module: Rex::Ui::Interactive

Overview

This class implements the stubs that are needed to provide an interactive user interface that is backed against something arbitrary.

Instance Attribute Summary collapse

Attributes included from Subscriber::Input

#user_input

Attributes included from Subscriber::Output

#user_output

Instance Method Summary collapse

Methods included from Subscriber

#copy_ui, #init_ui, #reset_ui

Methods included from Subscriber::Input

#gets

Methods included from Subscriber::Output

#flush, #print, #print_blank_line, #print_error, #print_good, #print_line, #print_status, #print_warning

Instance Attribute Details

#completedObject

Whether or not the session has completed interaction



126
127
128
# File 'lib/rex/ui/interactive.rb', line 126

def completed
  @completed
end

#interactingObject

Whether or not the session is currently being interacted with



116
117
118
# File 'lib/rex/ui/interactive.rb', line 116

def interacting
  @interacting
end

#next_sessionObject

If another session needs interaction, this is where it goes



121
122
123
# File 'lib/rex/ui/interactive.rb', line 121

def next_session
  @next_session
end

#on_command_procObject

Returns the value of attribute on_command_proc.



129
130
131
# File 'lib/rex/ui/interactive.rb', line 129

def on_command_proc
  @on_command_proc
end

#on_print_procObject

Returns the value of attribute on_print_proc.



128
129
130
# File 'lib/rex/ui/interactive.rb', line 128

def on_print_proc
  @on_print_proc
end

#on_run_command_error_procProc?

A function to be run when running a session command hits an error

Returns:

  • (Proc, nil)

    A function to be run when running a session command hits an error



135
136
137
# File 'lib/rex/ui/interactive.rb', line 135

def on_run_command_error_proc
  @on_run_command_error_proc
end

#orig_suspendObject (protected)

The original suspend proc.



142
143
144
# File 'lib/rex/ui/interactive.rb', line 142

def orig_suspend
  @orig_suspend
end

#orig_usr1Object (protected)

Returns the value of attribute orig_usr1.



143
144
145
# File 'lib/rex/ui/interactive.rb', line 143

def orig_usr1
  @orig_usr1
end

#orig_winchObject (protected)

Returns the value of attribute orig_winch.



144
145
146
# File 'lib/rex/ui/interactive.rb', line 144

def orig_winch
  @orig_winch
end

Instance Method Details

#_interactObject (protected)

Stub method that is meant to handler interaction



149
150
# File 'lib/rex/ui/interactive.rb', line 149

def _interact
end

#_interact_completeObject (protected)

Called when interaction has completed and one of the sides has closed.



169
170
171
# File 'lib/rex/ui/interactive.rb', line 169

def _interact_complete
  true
end

#_interruptObject (protected)

Called when an interrupt is sent.



155
156
157
# File 'lib/rex/ui/interactive.rb', line 155

def _interrupt
  true
end

#_local_fdObject (protected)

The local file descriptor handle.



196
197
198
# File 'lib/rex/ui/interactive.rb', line 196

def _local_fd
  user_input.fd
end

#_remote_fd(stream) ⇒ Object (protected)

The remote file descriptor handle.



203
204
205
# File 'lib/rex/ui/interactive.rb', line 203

def _remote_fd(stream)
  stream.fd
end

#_stream_read_local_write_remote(stream) ⇒ Object (protected)

Read from local and write to remote.



186
187
188
189
190
191
# File 'lib/rex/ui/interactive.rb', line 186

def _stream_read_local_write_remote(stream)
  data = user_input.gets

  self.on_command_proc.call(data) if self.on_command_proc
  stream.put(data)
end

#_stream_read_remote_write_local(stream) ⇒ Object (protected)

Read from remote and write to local.



176
177
178
179
180
181
# File 'lib/rex/ui/interactive.rb', line 176

def _stream_read_remote_write_local(stream)
  data = stream.get

  self.on_print_proc.call(data) if self.on_print_proc
  user_output.print(data)
end

#_suspendObject (protected)

Called when a suspend is sent.



162
163
164
# File 'lib/rex/ui/interactive.rb', line 162

def _suspend
  false
end

#_winchObject (protected)



298
299
# File 'lib/rex/ui/interactive.rb', line 298

def _winch
end

#detachObject

Stops the current interaction



104
105
106
107
108
109
110
111
# File 'lib/rex/ui/interactive.rb', line 104

def detach
  if (self.interacting)
    self.interacting = false
    while(not self.completed)
      ::IO.select(nil, nil, nil, 0.25)
    end
  end
end

#handle_suspendObject (protected)

Installs a signal handler to monitor suspend signal notifications.



236
237
238
239
240
241
242
243
244
245
# File 'lib/rex/ui/interactive.rb', line 236

def handle_suspend
  if orig_suspend.nil?
    begin
      self.orig_suspend = Signal.trap("TSTP") do
        Thread.new { _suspend }.join
      end
    rescue
    end
  end
end

#handle_usr1Object (protected)



264
265
266
267
268
269
270
271
272
273
# File 'lib/rex/ui/interactive.rb', line 264

def handle_usr1
  if orig_usr1.nil?
    begin
      self.orig_usr1 = Signal.trap("USR1") do
        Thread.new { _usr1 }.join
      end
    rescue
    end
  end
end

#handle_winchObject (protected)



275
276
277
278
279
280
281
282
283
284
# File 'lib/rex/ui/interactive.rb', line 275

def handle_winch
  if orig_winch.nil?
    begin
      self.orig_winch = Signal.trap("WINCH") do
        Thread.new { _winch }.join
      end
    rescue
    end
  end
end

#interact(user_input, user_output) ⇒ Object

Starts interacting with the session at the most raw level, simply forwarding input from user_input to rstream and forwarding input from rstream to user_output.



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/rex/ui/interactive.rb', line 24

def interact(user_input, user_output)

  # Detach from any existing console
  if self.interacting
    detach()
  end

  init_ui(user_input, user_output)

  self.interacting = true
  self.completed = false

  eof = false

  # Start the readline stdin monitor
  # XXX disabled
  # user_input.readline_start() if user_input.supports_readline

  # Handle suspend notifications
  handle_suspend

  handle_usr1

  handle_winch

  # As long as we're interacting...
  while (self.interacting == true)

    begin
      _interact

    rescue Interrupt
      # If we get an interrupt exception, ask the user if they want to
      # abort the interaction.  If they do, then we return out of
      # the interact function and call it a day.
      eof = true if (_interrupt)

    rescue EOFError, Errno::ECONNRESET, IOError
      # If we reach EOF or the connection is reset...
      eof = true

    end

    break if eof
  end

  begin

    # Restore the suspend handler
    restore_suspend

    restore_winch

    # If we've hit eof, call the interact complete handler
    _interact_complete if (eof == true)

    # Shutdown the readline thread
    # XXX disabled
    # user_input.readline_stop() if user_input.supports_readline

    # Detach from the input/output handles
    reset_ui()

  ensure
    # Mark this as completed
    self.completed = true
  end

  # if another session was requested, store it
  next_session = self.next_session
  # clear the value from the object
  self.next_session = nil

  # return this session id
  return next_session
end

#interact_stream(stream) ⇒ Object (protected)

Interacts with two streaming connections, reading data from one and writing it to the other. Both are expected to implement Rex::IO::Stream.



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/rex/ui/interactive.rb', line 211

def interact_stream(stream)
  while self.interacting && _remote_fd(stream)

    # Select input and rstream
    sd = Rex::ThreadSafe.select([ _local_fd, _remote_fd(stream) ], nil, nil, 0.25)

    # Cycle through the items that have data
    # From the stream?  Write to user_output.
    sd[0].each { |s|
      if (s == _remote_fd(stream))
        _stream_read_remote_write_local(stream)
      # From user_input?  Write to stream.
      elsif (s == _local_fd)
        _stream_read_local_write_remote(stream)
      end
    } if (sd)

    Thread.pass
  end
end

#prompt(query) ⇒ Object (protected)

Prompt the user for input if possible. XXX: This is not thread-safe on Windows



317
318
319
320
321
322
# File 'lib/rex/ui/interactive.rb', line 317

def prompt(query)
  if (user_output and user_input)
    user_output.print("\n" + query)
    user_input.sysread(2)
  end
end

#prompt_yesno(query) ⇒ Object (protected)

Check the return value of a yes/no prompt



327
328
329
# File 'lib/rex/ui/interactive.rb', line 327

def prompt_yesno(query)
  (prompt(query + " [y/N]  ") =~ /^y/i) ? true : false
end

#restore_suspendObject (protected)

Restores the previously installed signal handler for suspend notifications.



252
253
254
255
256
257
258
259
260
261
262
# File 'lib/rex/ui/interactive.rb', line 252

def restore_suspend
  begin
    if orig_suspend
      Signal.trap("TSTP", orig_suspend)
    else
      Signal.trap("TSTP", "DEFAULT")
    end
    self.orig_suspend = nil
  rescue
  end
end

#restore_usr1Object (protected)



301
302
303
304
305
306
307
308
309
310
311
# File 'lib/rex/ui/interactive.rb', line 301

def restore_usr1
  begin
    if orig_usr1
      Signal.trap("USR1", orig_usr1)
    else
      Signal.trap("USR1", "DEFAULT")
    end
    self.orig_usr1 = nil
  rescue
  end
end

#restore_winchObject (protected)



286
287
288
289
290
291
292
293
294
295
296
# File 'lib/rex/ui/interactive.rb', line 286

def restore_winch
  begin
    if orig_winch
      Signal.trap("WINCH", orig_winch)
    else
      Signal.trap("WINCH", "DEFAULT")
    end
    self.orig_winch = nil
  rescue
  end
end