hrr_rb_ssh 0.3.0.pre3 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +61 -3
- data/demo/client.rb +58 -0
- data/hrr_rb_ssh.gemspec +2 -2
- data/lib/hrr_rb_ssh/authentication/method/keyboard_interactive.rb +34 -0
- data/lib/hrr_rb_ssh/authentication/method/none.rb +13 -0
- data/lib/hrr_rb_ssh/authentication/method/password.rb +18 -0
- data/lib/hrr_rb_ssh/authentication/method/publickey/algorithm/functionable.rb +22 -0
- data/lib/hrr_rb_ssh/authentication/method/publickey.rb +49 -0
- data/lib/hrr_rb_ssh/authentication.rb +47 -1
- data/lib/hrr_rb_ssh/client.rb +198 -0
- data/lib/hrr_rb_ssh/connection/channel/channel_type/direct_tcpip.rb +6 -3
- data/lib/hrr_rb_ssh/connection/channel/channel_type/forwarded_tcpip.rb +6 -3
- data/lib/hrr_rb_ssh/connection/channel/channel_type/session.rb +7 -1
- data/lib/hrr_rb_ssh/connection/channel.rb +308 -79
- data/lib/hrr_rb_ssh/connection.rb +99 -38
- data/lib/hrr_rb_ssh/logger.rb +5 -5
- data/lib/hrr_rb_ssh/server.rb +3 -3
- data/lib/hrr_rb_ssh/transport/kex_algorithm/diffie_hellman.rb +37 -32
- data/lib/hrr_rb_ssh/transport/kex_algorithm/diffie_hellman_group_exchange.rb +80 -46
- data/lib/hrr_rb_ssh/transport/kex_algorithm/elliptic_curve_diffie_hellman.rb +37 -32
- data/lib/hrr_rb_ssh/transport.rb +46 -10
- data/lib/hrr_rb_ssh/version.rb +1 -1
- data/lib/hrr_rb_ssh.rb +1 -0
- metadata +9 -8
@@ -27,6 +27,9 @@ module HrrRbSsh
|
|
27
27
|
if @sender_thread_finished && @receiver_thread_finished
|
28
28
|
@logger.info { "closing forwarded-tcpip" }
|
29
29
|
@socket.close
|
30
|
+
@logger.info { "closing channel IOs" }
|
31
|
+
@channel.io.each{ |io| io.close rescue nil }
|
32
|
+
@logger.info { "channel IOs closed" }
|
30
33
|
@channel.close from=:channel_type_instance
|
31
34
|
@logger.info { "forwarded-tcpip closed" }
|
32
35
|
end
|
@@ -43,15 +46,15 @@ module HrrRbSsh
|
|
43
46
|
@channel.io[1].write s.readpartial(10240)
|
44
47
|
rescue EOFError
|
45
48
|
@logger.info { "socket is EOF" }
|
46
|
-
@channel.io[1].close
|
49
|
+
@channel.io[1].close rescue nil
|
47
50
|
break
|
48
51
|
rescue IOError
|
49
52
|
@logger.info { "socket is closed" }
|
50
|
-
@channel.io[1].close
|
53
|
+
@channel.io[1].close rescue nil
|
51
54
|
break
|
52
55
|
rescue => e
|
53
56
|
@logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
54
|
-
@channel.io[1].close
|
57
|
+
@channel.io[1].close rescue nil
|
55
58
|
break
|
56
59
|
end
|
57
60
|
end
|
@@ -18,7 +18,10 @@ module HrrRbSsh
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def start
|
21
|
-
@
|
21
|
+
case @connection.mode
|
22
|
+
when Mode::SERVER
|
23
|
+
@proc_chain_thread = proc_chain_thread
|
24
|
+
end
|
22
25
|
end
|
23
26
|
|
24
27
|
def close
|
@@ -42,6 +45,9 @@ module HrrRbSsh
|
|
42
45
|
exitstatus = 1
|
43
46
|
ensure
|
44
47
|
@logger.info { "closing proc chain thread" }
|
48
|
+
@logger.info { "closing channel IOs" }
|
49
|
+
@channel.io.each{ |io| io.close rescue nil }
|
50
|
+
@logger.info { "channel IOs closed" }
|
45
51
|
@logger.info { "wait for sending output" }
|
46
52
|
@channel.wait_until_senders_closed
|
47
53
|
@logger.info { "sending output finished" }
|
@@ -2,6 +2,8 @@
|
|
2
2
|
# vim: et ts=2 sw=2
|
3
3
|
|
4
4
|
require 'socket'
|
5
|
+
require 'thread'
|
6
|
+
require 'monitor'
|
5
7
|
require 'hrr_rb_ssh/logger'
|
6
8
|
require 'hrr_rb_ssh/connection/channel/channel_type'
|
7
9
|
|
@@ -19,7 +21,8 @@ module HrrRbSsh
|
|
19
21
|
:local_maximum_packet_size,
|
20
22
|
:remote_window_size,
|
21
23
|
:remote_maximum_packet_size,
|
22
|
-
:receive_message_queue
|
24
|
+
:receive_message_queue,
|
25
|
+
:exit_status
|
23
26
|
|
24
27
|
def initialize connection, message, socket=nil
|
25
28
|
@logger = Logger.new self.class.name
|
@@ -38,60 +41,81 @@ module HrrRbSsh
|
|
38
41
|
|
39
42
|
@receive_message_queue = Queue.new
|
40
43
|
@receive_data_queue = Queue.new
|
44
|
+
@receive_extended_data_queue = Queue.new
|
41
45
|
|
42
46
|
@r_io_in, @w_io_in = IO.pipe
|
43
47
|
@r_io_out, @w_io_out = IO.pipe
|
44
48
|
@r_io_err, @w_io_err = IO.pipe
|
45
49
|
|
50
|
+
@channel_closing_monitor = Monitor.new
|
51
|
+
|
46
52
|
@closed = nil
|
53
|
+
@exit_status = nil
|
47
54
|
end
|
48
55
|
|
49
56
|
def set_remote_parameters message
|
50
57
|
@remote_channel = message[:'sender channel']
|
51
|
-
@remote_window_size
|
58
|
+
@remote_window_size = message[:'initial window size']
|
52
59
|
@remote_maximum_packet_size = message[:'maximum packet size']
|
53
60
|
end
|
54
61
|
|
55
62
|
def io
|
56
|
-
|
63
|
+
case @connection.mode
|
64
|
+
when Mode::SERVER
|
65
|
+
[@r_io_in, @w_io_out, @w_io_err]
|
66
|
+
when Mode::CLIENT
|
67
|
+
[@w_io_in, @r_io_out, @r_io_err]
|
68
|
+
end
|
57
69
|
end
|
58
70
|
|
59
71
|
def start
|
60
72
|
@channel_loop_thread = channel_loop_thread
|
61
|
-
@
|
62
|
-
|
63
|
-
|
64
|
-
|
73
|
+
case @connection.mode
|
74
|
+
when Mode::SERVER
|
75
|
+
@out_sender_thread = out_sender_thread
|
76
|
+
@err_sender_thread = err_sender_thread
|
77
|
+
@receiver_thread = receiver_thread
|
78
|
+
@channel_type_instance.start
|
79
|
+
when Mode::CLIENT
|
80
|
+
@out_receiver_thread = out_receiver_thread
|
81
|
+
@err_receiver_thread = err_receiver_thread
|
82
|
+
@sender_thread = sender_thread
|
83
|
+
@channel_type_instance.start
|
84
|
+
end
|
65
85
|
@closed = false
|
86
|
+
@logger.debug { "in start: #{@waiting_thread}" }
|
87
|
+
@waiting_thread.wakeup if @waiting_thread
|
88
|
+
end
|
89
|
+
|
90
|
+
def wait_until_started
|
91
|
+
@waiting_thread = Thread.current
|
92
|
+
@logger.debug { "in wait_until_started: #{@waiting_thread}" }
|
93
|
+
Thread.stop
|
66
94
|
end
|
67
95
|
|
68
96
|
def wait_until_senders_closed
|
69
|
-
[
|
97
|
+
[
|
98
|
+
@out_sender_thread,
|
99
|
+
@err_sender_thread,
|
100
|
+
].each{ |t|
|
70
101
|
begin
|
71
|
-
|
72
|
-
rescue
|
73
|
-
|
102
|
+
t.join if t.instance_of? Thread
|
103
|
+
rescue => e
|
104
|
+
@logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
74
105
|
end
|
75
106
|
}
|
76
|
-
[@out_sender_thread, @err_sender_thread].select{ |t| t.instance_of? Thread }.each(&:join)
|
77
107
|
end
|
78
108
|
|
79
109
|
def close from=:outside, exitstatus=0
|
80
|
-
|
81
|
-
|
82
|
-
|
110
|
+
@channel_closing_monitor.synchronize {
|
111
|
+
return if @closed
|
112
|
+
@logger.info { "close channel" }
|
113
|
+
@closed = true
|
114
|
+
}
|
83
115
|
unless from == :channel_type_instance
|
84
116
|
@channel_type_instance.close
|
85
117
|
end
|
86
118
|
@receive_message_queue.close
|
87
|
-
@receive_data_queue.close
|
88
|
-
[@r_io_in, @w_io_in, @r_io_out, @w_io_out, @r_io_err, @w_io_err].each{ |io|
|
89
|
-
begin
|
90
|
-
io.close
|
91
|
-
rescue IOError # for compatibility for Ruby version < 2.3
|
92
|
-
Thread.pass
|
93
|
-
end
|
94
|
-
}
|
95
119
|
begin
|
96
120
|
if from == :channel_type_instance
|
97
121
|
send_channel_eof
|
@@ -111,6 +135,24 @@ module HrrRbSsh
|
|
111
135
|
@logger.info { "channel closed" }
|
112
136
|
end
|
113
137
|
|
138
|
+
def wait_until_closed
|
139
|
+
[
|
140
|
+
@out_sender_thread,
|
141
|
+
@err_sender_thread,
|
142
|
+
@receiver_thread,
|
143
|
+
@out_receiver_thread,
|
144
|
+
@err_receiver_thread,
|
145
|
+
@sender_thread,
|
146
|
+
@channel_loop_thread
|
147
|
+
].each{ |t|
|
148
|
+
begin
|
149
|
+
t.join if t.instance_of? Thread
|
150
|
+
rescue => e
|
151
|
+
@logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
152
|
+
end
|
153
|
+
}
|
154
|
+
end
|
155
|
+
|
114
156
|
def closed?
|
115
157
|
@closed
|
116
158
|
end
|
@@ -118,44 +160,60 @@ module HrrRbSsh
|
|
118
160
|
def channel_loop_thread
|
119
161
|
Thread.start do
|
120
162
|
@logger.info { "start channel loop thread" }
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
@
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
@
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
163
|
+
begin
|
164
|
+
loop do
|
165
|
+
begin
|
166
|
+
message = @receive_message_queue.deq
|
167
|
+
if message.nil? && @receive_message_queue.closed?
|
168
|
+
break
|
169
|
+
end
|
170
|
+
case message[:'message number']
|
171
|
+
when Message::SSH_MSG_CHANNEL_EOF::VALUE
|
172
|
+
@receive_data_queue.close
|
173
|
+
@receive_extended_data_queue.close
|
174
|
+
when Message::SSH_MSG_CHANNEL_REQUEST::VALUE
|
175
|
+
@logger.info { "received channel request: #{message[:'request type']}" }
|
176
|
+
case @connection.mode
|
177
|
+
when Mode::SERVER
|
178
|
+
begin
|
179
|
+
@channel_type_instance.request message
|
180
|
+
rescue => e
|
181
|
+
@logger.warn { "request failed: #{e.message}" }
|
182
|
+
send_channel_failure if message[:'want reply']
|
183
|
+
else
|
184
|
+
send_channel_success if message[:'want reply']
|
185
|
+
end
|
186
|
+
when Mode::CLIENT
|
187
|
+
case message[:'request type']
|
188
|
+
when "exit-status"
|
189
|
+
@logger.info { "exit status: #{message[:'exit status']}" }
|
190
|
+
@exit_status = message[:'exit status'].to_i
|
191
|
+
end
|
138
192
|
end
|
193
|
+
when Message::SSH_MSG_CHANNEL_DATA::VALUE
|
194
|
+
@logger.info { "received channel data" }
|
195
|
+
local_channel = message[:'recipient channel']
|
196
|
+
@receive_data_queue.enq message[:'data']
|
197
|
+
when Message::SSH_MSG_CHANNEL_EXTENDED_DATA::VALUE
|
198
|
+
@logger.info { "received channel extended data" }
|
199
|
+
local_channel = message[:'recipient channel']
|
200
|
+
@receive_extended_data_queue.enq message[:'data']
|
201
|
+
when Message::SSH_MSG_CHANNEL_WINDOW_ADJUST::VALUE
|
202
|
+
@logger.debug { "received channel window adjust" }
|
203
|
+
@remote_window_size = [@remote_window_size + message[:'bytes to add'], 0xffff_ffff].min
|
139
204
|
else
|
140
|
-
|
141
|
-
send_channel_success
|
142
|
-
end
|
205
|
+
@logger.warn { "received unsupported message: #{message.inspect}" }
|
143
206
|
end
|
144
|
-
|
145
|
-
@logger.
|
146
|
-
|
147
|
-
|
148
|
-
when Message::SSH_MSG_CHANNEL_WINDOW_ADJUST::VALUE
|
149
|
-
@logger.debug { "received channel window adjust" }
|
150
|
-
@remote_window_size = [@remote_window_size + message[:'bytes to add'], 0xffff_ffff].min
|
151
|
-
else
|
152
|
-
@logger.warn { "received unsupported message: #{message.inspect}" }
|
207
|
+
rescue => e
|
208
|
+
@logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
209
|
+
close from=:channel_loop_thread
|
210
|
+
break
|
153
211
|
end
|
154
|
-
rescue => e
|
155
|
-
@logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
156
|
-
close from=:channel_loop_thread
|
157
|
-
break
|
158
212
|
end
|
213
|
+
ensure
|
214
|
+
@logger.info { "closing channel loop thread" }
|
215
|
+
@receive_data_queue.close
|
216
|
+
@receive_extended_data_queue.close
|
159
217
|
end
|
160
218
|
@logger.info { "channel loop thread closed" }
|
161
219
|
end
|
@@ -175,17 +233,11 @@ module HrrRbSsh
|
|
175
233
|
sending_data = data[0, sendable_size]
|
176
234
|
send_channel_data sending_data if sendable_size > 0
|
177
235
|
@remote_window_size -= sendable_size
|
178
|
-
rescue EOFError => e
|
179
|
-
|
180
|
-
@r_io_out.close
|
181
|
-
rescue IOError # for compatibility for Ruby version < 2.3
|
182
|
-
Thread.pass
|
183
|
-
end
|
184
|
-
rescue IOError => e
|
185
|
-
@logger.warn { "channel IO is closed" }
|
186
|
-
close
|
236
|
+
rescue EOFError, IOError => e
|
237
|
+
@r_io_out.close rescue nil
|
187
238
|
rescue => e
|
188
239
|
@logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
240
|
+
@r_io_out.close rescue nil
|
189
241
|
close
|
190
242
|
end
|
191
243
|
end
|
@@ -207,17 +259,11 @@ module HrrRbSsh
|
|
207
259
|
sending_data = data[0, sendable_size]
|
208
260
|
send_channel_extended_data sending_data if sendable_size > 0
|
209
261
|
@remote_window_size -= sendable_size
|
210
|
-
rescue EOFError => e
|
211
|
-
|
212
|
-
@r_io_err.close
|
213
|
-
rescue IOError # for compatibility for Ruby version < 2.3
|
214
|
-
Thread.pass
|
215
|
-
end
|
216
|
-
rescue IOError => e
|
217
|
-
@logger.warn { "channel IO is closed" }
|
218
|
-
close
|
262
|
+
rescue EOFError, IOError => e
|
263
|
+
@r_io_err.close rescue nil
|
219
264
|
rescue => e
|
220
265
|
@logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
266
|
+
@r_io_err.close rescue nil
|
221
267
|
close
|
222
268
|
end
|
223
269
|
end
|
@@ -233,9 +279,9 @@ module HrrRbSsh
|
|
233
279
|
data = @receive_data_queue.deq
|
234
280
|
if data.nil? && @receive_data_queue.closed?
|
235
281
|
@logger.info { "closing receiver thread" }
|
236
|
-
@logger.info { "closing
|
237
|
-
@w_io_in.
|
238
|
-
@logger.info { "
|
282
|
+
@logger.info { "closing w_io_in" }
|
283
|
+
@w_io_in.close
|
284
|
+
@logger.info { "w_io_in closed" }
|
239
285
|
break
|
240
286
|
end
|
241
287
|
@w_io_in.write data
|
@@ -245,8 +291,7 @@ module HrrRbSsh
|
|
245
291
|
send_channel_window_adjust
|
246
292
|
@local_window_size += INITIAL_WINDOW_SIZE
|
247
293
|
end
|
248
|
-
rescue IOError => e
|
249
|
-
@logger.warn { "channel IO is closed" }
|
294
|
+
rescue Errno::EPIPE, IOError => e
|
250
295
|
close
|
251
296
|
break
|
252
297
|
rescue => e
|
@@ -259,6 +304,98 @@ module HrrRbSsh
|
|
259
304
|
}
|
260
305
|
end
|
261
306
|
|
307
|
+
def out_receiver_thread
|
308
|
+
Thread.start {
|
309
|
+
@logger.info { "start out receiver thread" }
|
310
|
+
loop do
|
311
|
+
begin
|
312
|
+
data = @receive_data_queue.deq
|
313
|
+
if data.nil? && @receive_data_queue.closed?
|
314
|
+
@logger.info { "closing out receiver thread" }
|
315
|
+
@logger.info { "closing w_io_out" }
|
316
|
+
@w_io_out.close
|
317
|
+
@logger.info { "w_io_out closed" }
|
318
|
+
break
|
319
|
+
end
|
320
|
+
@w_io_out.write data
|
321
|
+
@local_window_size -= data.size
|
322
|
+
if @local_window_size < INITIAL_WINDOW_SIZE/2
|
323
|
+
@logger.info { "send channel window adjust" }
|
324
|
+
send_channel_window_adjust
|
325
|
+
@local_window_size += INITIAL_WINDOW_SIZE
|
326
|
+
end
|
327
|
+
rescue Errno::EPIPE, IOError => e
|
328
|
+
close
|
329
|
+
break
|
330
|
+
rescue => e
|
331
|
+
@logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
332
|
+
close
|
333
|
+
break
|
334
|
+
end
|
335
|
+
end
|
336
|
+
@logger.info { "out receiver thread closed" }
|
337
|
+
}
|
338
|
+
end
|
339
|
+
|
340
|
+
def err_receiver_thread
|
341
|
+
Thread.start {
|
342
|
+
@logger.info { "start err receiver thread" }
|
343
|
+
loop do
|
344
|
+
begin
|
345
|
+
data = @receive_extended_data_queue.deq
|
346
|
+
if data.nil? && @receive_extended_data_queue.closed?
|
347
|
+
@logger.info { "closing err receiver thread" }
|
348
|
+
@logger.info { "closing w_io_err" }
|
349
|
+
@w_io_err.close
|
350
|
+
@logger.info { "w_io_err closed" }
|
351
|
+
break
|
352
|
+
end
|
353
|
+
@w_io_err.write data
|
354
|
+
@local_window_size -= data.size
|
355
|
+
if @local_window_size < INITIAL_WINDOW_SIZE/2
|
356
|
+
@logger.info { "send channel window adjust" }
|
357
|
+
send_channel_window_adjust
|
358
|
+
@local_window_size += INITIAL_WINDOW_SIZE
|
359
|
+
end
|
360
|
+
rescue Error::EPIPE, IOError => e
|
361
|
+
close
|
362
|
+
break
|
363
|
+
rescue => e
|
364
|
+
@logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
365
|
+
close
|
366
|
+
break
|
367
|
+
end
|
368
|
+
end
|
369
|
+
@logger.info { "err receiver thread closed" }
|
370
|
+
}
|
371
|
+
end
|
372
|
+
|
373
|
+
def sender_thread
|
374
|
+
Thread.start {
|
375
|
+
@logger.info { "start sender thread" }
|
376
|
+
loop do
|
377
|
+
if @r_io_in.closed?
|
378
|
+
@logger.info { "closing sender thread" }
|
379
|
+
break
|
380
|
+
end
|
381
|
+
begin
|
382
|
+
data = @r_io_in.readpartial(10240)
|
383
|
+
sendable_size = [data.size, @remote_window_size].min
|
384
|
+
sending_data = data[0, sendable_size]
|
385
|
+
send_channel_data sending_data if sendable_size > 0
|
386
|
+
@remote_window_size -= sendable_size
|
387
|
+
rescue EOFError, IOError => e
|
388
|
+
@r_io_in.close rescue nil
|
389
|
+
rescue => e
|
390
|
+
@logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
391
|
+
@r_io_in.close rescue nil
|
392
|
+
close
|
393
|
+
end
|
394
|
+
end
|
395
|
+
@logger.info { "sender thread closed" }
|
396
|
+
}
|
397
|
+
end
|
398
|
+
|
262
399
|
def send_channel_success
|
263
400
|
message = {
|
264
401
|
:'message number' => Message::SSH_MSG_CHANNEL_SUCCESS::VALUE,
|
@@ -308,6 +445,98 @@ module HrrRbSsh
|
|
308
445
|
@connection.send payload
|
309
446
|
end
|
310
447
|
|
448
|
+
def send_channel_request_pty_req term_env_var_val, term_width_chars, term_height_rows, term_width_pixel, term_height_pixel, encoded_term_modes
|
449
|
+
message = {
|
450
|
+
:'message number' => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
|
451
|
+
:'recipient channel' => @remote_channel,
|
452
|
+
:'request type' => "pty-req",
|
453
|
+
:'want reply' => false,
|
454
|
+
:'TERM environment variable value' => term_env_var_val,
|
455
|
+
:'terminal width, characters' => term_width_chars,
|
456
|
+
:'terminal height, rows' => term_height_rows,
|
457
|
+
:'terminal width, pixels' => term_width_pixel,
|
458
|
+
:'terminal height, pixels' => term_height_pixel,
|
459
|
+
:'encoded terminal modes' => encoded_term_modes,
|
460
|
+
}
|
461
|
+
payload = Message::SSH_MSG_CHANNEL_REQUEST.encode message
|
462
|
+
@connection.send payload
|
463
|
+
end
|
464
|
+
|
465
|
+
def send_channel_request_env variable_name, variable_value
|
466
|
+
message = {
|
467
|
+
:'message number' => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
|
468
|
+
:'recipient channel' => @remote_channel,
|
469
|
+
:'request type' => "env",
|
470
|
+
:'want reply' => false,
|
471
|
+
:'variable name' => variable_name,
|
472
|
+
:'variable value' => variable_value,
|
473
|
+
}
|
474
|
+
payload = Message::SSH_MSG_CHANNEL_REQUEST.encode message
|
475
|
+
@connection.send payload
|
476
|
+
end
|
477
|
+
|
478
|
+
def send_channel_request_shell
|
479
|
+
message = {
|
480
|
+
:'message number' => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
|
481
|
+
:'recipient channel' => @remote_channel,
|
482
|
+
:'request type' => "shell",
|
483
|
+
:'want reply' => false,
|
484
|
+
}
|
485
|
+
payload = Message::SSH_MSG_CHANNEL_REQUEST.encode message
|
486
|
+
@connection.send payload
|
487
|
+
end
|
488
|
+
|
489
|
+
def send_channel_request_exec command
|
490
|
+
message = {
|
491
|
+
:'message number' => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
|
492
|
+
:'recipient channel' => @remote_channel,
|
493
|
+
:'request type' => "exec",
|
494
|
+
:'want reply' => false,
|
495
|
+
:'command' => command,
|
496
|
+
}
|
497
|
+
payload = Message::SSH_MSG_CHANNEL_REQUEST.encode message
|
498
|
+
@connection.send payload
|
499
|
+
end
|
500
|
+
|
501
|
+
def send_channel_request_subsystem subsystem_name
|
502
|
+
message = {
|
503
|
+
:'message number' => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
|
504
|
+
:'recipient channel' => @remote_channel,
|
505
|
+
:'request type' => "subsystem",
|
506
|
+
:'want reply' => false,
|
507
|
+
:'subsystem name' => subsystem_name,
|
508
|
+
}
|
509
|
+
payload = Message::SSH_MSG_CHANNEL_REQUEST.encode message
|
510
|
+
@connection.send payload
|
511
|
+
end
|
512
|
+
|
513
|
+
def send_channel_request_window_change term_width_cols, term_height_rows, term_width_pixel, term_height_pixel
|
514
|
+
message = {
|
515
|
+
:'message number' => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
|
516
|
+
:'recipient channel' => @remote_channel,
|
517
|
+
:'request type' => "window-change",
|
518
|
+
:'want reply' => false,
|
519
|
+
:'terminal width, columns' => term_width_cols,
|
520
|
+
:'terminal height, rows' => term_height_rows,
|
521
|
+
:'terminal width, pixels' => term_width_pixel,
|
522
|
+
:'terminal height, pixels' => term_height_pixel,
|
523
|
+
}
|
524
|
+
payload = Message::SSH_MSG_CHANNEL_REQUEST.encode message
|
525
|
+
@connection.send payload
|
526
|
+
end
|
527
|
+
|
528
|
+
def send_channel_request_signal signal_name
|
529
|
+
message = {
|
530
|
+
:'message number' => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
|
531
|
+
:'recipient channel' => @remote_channel,
|
532
|
+
:'request type' => "signal",
|
533
|
+
:'want reply' => false,
|
534
|
+
:'signal name' => signal_name,
|
535
|
+
}
|
536
|
+
payload = Message::SSH_MSG_CHANNEL_REQUEST.encode message
|
537
|
+
@connection.send payload
|
538
|
+
end
|
539
|
+
|
311
540
|
def send_channel_request_exit_status exitstatus
|
312
541
|
message = {
|
313
542
|
:'message number' => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
|