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

#orig_suspendObject (protected)

The original suspend proc.


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

def orig_suspend
  @orig_suspend
end

#orig_usr1Object (protected)

Returns the value of attribute orig_usr1.


137
138
139
# File 'lib/rex/ui/interactive.rb', line 137

def orig_usr1
  @orig_usr1
end

#orig_winchObject (protected)

Returns the value of attribute orig_winch.


138
139
140
# File 'lib/rex/ui/interactive.rb', line 138

def orig_winch
  @orig_winch
end

Instance Method Details

#_interactObject (protected)

Stub method that is meant to handler interaction


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

def _interact
end

#_interact_completeObject (protected)

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


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

def _interact_complete
  true
end

#_interruptObject (protected)

Called when an interrupt is sent.


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

def _interrupt
  true
end

#_local_fdObject (protected)

The local file descriptor handle.


190
191
192
# File 'lib/rex/ui/interactive.rb', line 190

def _local_fd
  user_input.fd
end

#_remote_fd(stream) ⇒ Object (protected)

The remote file descriptor handle.


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

def _remote_fd(stream)
  stream.fd
end

#_stream_read_local_write_remote(stream) ⇒ Object (protected)

Read from local and write to remote.


180
181
182
183
184
185
# File 'lib/rex/ui/interactive.rb', line 180

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.


170
171
172
173
174
175
# File 'lib/rex/ui/interactive.rb', line 170

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.


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

def _suspend
  false
end

#_winchObject (protected)


292
293
# File 'lib/rex/ui/interactive.rb', line 292

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.


230
231
232
233
234
235
236
237
238
239
# File 'lib/rex/ui/interactive.rb', line 230

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)


258
259
260
261
262
263
264
265
266
267
# File 'lib/rex/ui/interactive.rb', line 258

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)


269
270
271
272
273
274
275
276
277
278
# File 'lib/rex/ui/interactive.rb', line 269

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.


205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/rex/ui/interactive.rb', line 205

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


311
312
313
314
315
316
# File 'lib/rex/ui/interactive.rb', line 311

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


321
322
323
# File 'lib/rex/ui/interactive.rb', line 321

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.


246
247
248
249
250
251
252
253
254
255
256
# File 'lib/rex/ui/interactive.rb', line 246

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)


295
296
297
298
299
300
301
302
303
304
305
# File 'lib/rex/ui/interactive.rb', line 295

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)


280
281
282
283
284
285
286
287
288
289
290
# File 'lib/rex/ui/interactive.rb', line 280

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