net-ssh 6.2.0.rc2 → 6.3.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.github/workflows/ci.yml +27 -10
- data/.rubocop.yml +11 -1
- data/.rubocop_todo.yml +374 -173
- data/.travis.yml +10 -11
- data/CHANGES.txt +6 -0
- data/Gemfile +2 -0
- data/Gemfile.noed25519 +2 -0
- data/README.md +2 -2
- data/Rakefile +1 -0
- data/lib/net/ssh.rb +1 -2
- data/lib/net/ssh/authentication/agent.rb +4 -2
- data/lib/net/ssh/authentication/certificate.rb +3 -1
- data/lib/net/ssh/authentication/constants.rb +0 -1
- data/lib/net/ssh/authentication/ed25519.rb +6 -2
- data/lib/net/ssh/authentication/ed25519_loader.rb +4 -7
- data/lib/net/ssh/authentication/key_manager.rb +28 -29
- data/lib/net/ssh/authentication/methods/abstract.rb +0 -1
- data/lib/net/ssh/authentication/methods/hostbased.rb +0 -2
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +1 -1
- data/lib/net/ssh/authentication/methods/none.rb +5 -8
- data/lib/net/ssh/authentication/methods/password.rb +1 -2
- data/lib/net/ssh/authentication/methods/publickey.rb +0 -2
- data/lib/net/ssh/authentication/pageant.rb +89 -89
- data/lib/net/ssh/authentication/session.rb +14 -15
- data/lib/net/ssh/buffer.rb +10 -5
- data/lib/net/ssh/buffered_io.rb +18 -19
- data/lib/net/ssh/config.rb +29 -16
- data/lib/net/ssh/connection/channel.rb +71 -69
- data/lib/net/ssh/connection/constants.rb +0 -4
- data/lib/net/ssh/connection/event_loop.rb +22 -16
- data/lib/net/ssh/connection/keepalive.rb +12 -12
- data/lib/net/ssh/connection/session.rb +95 -94
- data/lib/net/ssh/connection/term.rb +56 -58
- data/lib/net/ssh/errors.rb +10 -10
- data/lib/net/ssh/key_factory.rb +0 -1
- data/lib/net/ssh/known_hosts.rb +79 -11
- data/lib/net/ssh/loggable.rb +8 -9
- data/lib/net/ssh/packet.rb +1 -1
- data/lib/net/ssh/prompt.rb +8 -10
- data/lib/net/ssh/proxy/command.rb +1 -1
- data/lib/net/ssh/proxy/errors.rb +2 -4
- data/lib/net/ssh/proxy/http.rb +17 -19
- data/lib/net/ssh/proxy/https.rb +6 -8
- data/lib/net/ssh/proxy/jump.rb +8 -10
- data/lib/net/ssh/proxy/socks4.rb +1 -3
- data/lib/net/ssh/proxy/socks5.rb +2 -4
- data/lib/net/ssh/service/forward.rb +3 -3
- data/lib/net/ssh/test.rb +1 -2
- data/lib/net/ssh/test/channel.rb +20 -22
- data/lib/net/ssh/test/extensions.rb +29 -29
- data/lib/net/ssh/test/kex.rb +6 -8
- data/lib/net/ssh/test/local_packet.rb +0 -2
- data/lib/net/ssh/test/packet.rb +2 -2
- data/lib/net/ssh/test/remote_packet.rb +5 -7
- data/lib/net/ssh/test/script.rb +21 -23
- data/lib/net/ssh/test/socket.rb +11 -14
- data/lib/net/ssh/transport/algorithms.rb +2 -1
- data/lib/net/ssh/transport/cipher_factory.rb +13 -13
- data/lib/net/ssh/transport/constants.rb +3 -3
- data/lib/net/ssh/transport/ctr.rb +4 -4
- data/lib/net/ssh/transport/hmac/abstract.rb +0 -1
- data/lib/net/ssh/transport/hmac/md5.rb +0 -2
- data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
- data/lib/net/ssh/transport/hmac/none.rb +0 -2
- data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
- data/lib/net/ssh/transport/identity_cipher.rb +10 -12
- data/lib/net/ssh/transport/kex.rb +2 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256.rb +1 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +4 -4
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +0 -1
- data/lib/net/ssh/transport/key_expander.rb +6 -7
- data/lib/net/ssh/transport/openssl.rb +6 -11
- data/lib/net/ssh/transport/packet_stream.rb +1 -2
- data/lib/net/ssh/transport/server_version.rb +17 -16
- data/lib/net/ssh/transport/session.rb +3 -1
- data/lib/net/ssh/transport/state.rb +42 -42
- data/lib/net/ssh/verifiers/accept_new.rb +0 -2
- data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +1 -2
- data/lib/net/ssh/verifiers/always.rb +6 -4
- data/lib/net/ssh/verifiers/never.rb +0 -2
- data/lib/net/ssh/version.rb +2 -2
- data/net-ssh-public_cert.pem +8 -8
- data/net-ssh.gemspec +2 -2
- data/support/ssh_tunnel_bug.rb +3 -3
- metadata +14 -13
- metadata.gz.sig +0 -0
|
@@ -11,7 +11,6 @@ require 'net/ssh/authentication/methods/keyboard_interactive'
|
|
|
11
11
|
module Net
|
|
12
12
|
module SSH
|
|
13
13
|
module Authentication
|
|
14
|
-
|
|
15
14
|
# Raised if the current authentication method is not allowed
|
|
16
15
|
class DisallowedMethod < Net::SSH::Exception
|
|
17
16
|
end
|
|
@@ -70,22 +69,21 @@ module Net
|
|
|
70
69
|
attempted = []
|
|
71
70
|
|
|
72
71
|
@auth_methods.each do |name|
|
|
72
|
+
next unless @allowed_auth_methods.include?(name)
|
|
73
|
+
|
|
74
|
+
attempted << name
|
|
75
|
+
|
|
76
|
+
debug { "trying #{name}" }
|
|
73
77
|
begin
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
debug {
|
|
78
|
-
|
|
79
|
-
auth_class = Methods.const_get(name.split(/\W+/).map { |p| p.capitalize }.join)
|
|
80
|
-
method = auth_class.new(self, key_manager: key_manager, password_prompt: options[:password_prompt])
|
|
81
|
-
rescue NameError
|
|
82
|
-
debug {"Mechanism #{name} was requested, but isn't a known type. Ignoring it."}
|
|
83
|
-
next
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
return true if method.authenticate(next_service, username, password)
|
|
87
|
-
rescue Net::SSH::Authentication::DisallowedMethod
|
|
78
|
+
auth_class = Methods.const_get(name.split(/\W+/).map { |p| p.capitalize }.join)
|
|
79
|
+
method = auth_class.new(self, key_manager: key_manager, password_prompt: options[:password_prompt])
|
|
80
|
+
rescue NameError
|
|
81
|
+
debug {"Mechanism #{name} was requested, but isn't a known type. Ignoring it."}
|
|
82
|
+
next
|
|
88
83
|
end
|
|
84
|
+
|
|
85
|
+
return true if method.authenticate(next_service, username, password)
|
|
86
|
+
rescue Net::SSH::Authentication::DisallowedMethod
|
|
89
87
|
end
|
|
90
88
|
|
|
91
89
|
error { "all authorization methods failed (tried #{attempted.join(', ')})" }
|
|
@@ -129,6 +127,7 @@ module Net
|
|
|
129
127
|
def expect_message(type)
|
|
130
128
|
message = next_message
|
|
131
129
|
raise Net::SSH::Exception, "expected #{type}, got #{message.type} (#{message})" unless message.type == type
|
|
130
|
+
|
|
132
131
|
message
|
|
133
132
|
end
|
|
134
133
|
|
data/lib/net/ssh/buffer.rb
CHANGED
|
@@ -5,7 +5,6 @@ require 'net/ssh/authentication/ed25519_loader'
|
|
|
5
5
|
|
|
6
6
|
module Net
|
|
7
7
|
module SSH
|
|
8
|
-
|
|
9
8
|
# Net::SSH::Buffer is a flexible class for building and parsing binary
|
|
10
9
|
# data packets. It provides a stream-like interface for sequentially
|
|
11
10
|
# reading data items from the buffer, as well as a useful helper method
|
|
@@ -71,7 +70,7 @@ module Net
|
|
|
71
70
|
|
|
72
71
|
# Creates a new buffer, initialized to the given content. The position
|
|
73
72
|
# is initialized to the beginning of the buffer.
|
|
74
|
-
def initialize(content=
|
|
73
|
+
def initialize(content=String.new)
|
|
75
74
|
@content = content.to_s
|
|
76
75
|
@position = 0
|
|
77
76
|
end
|
|
@@ -118,7 +117,7 @@ module Net
|
|
|
118
117
|
# Resets the buffer, making it empty. Also, resets the read position to
|
|
119
118
|
# 0.
|
|
120
119
|
def clear!
|
|
121
|
-
@content =
|
|
120
|
+
@content = String.new
|
|
122
121
|
@position = 0
|
|
123
122
|
end
|
|
124
123
|
|
|
@@ -134,7 +133,7 @@ module Net
|
|
|
134
133
|
# optimize for a fairly common case
|
|
135
134
|
clear!
|
|
136
135
|
elsif n > 0
|
|
137
|
-
@content = @content[n..-1] ||
|
|
136
|
+
@content = @content[n..-1] || String.new
|
|
138
137
|
@position -= n
|
|
139
138
|
@position = 0 if @position < 0
|
|
140
139
|
end
|
|
@@ -237,6 +236,7 @@ module Net
|
|
|
237
236
|
def read_bignum
|
|
238
237
|
data = read_string
|
|
239
238
|
return unless data
|
|
239
|
+
|
|
240
240
|
OpenSSL::BN.new(data, 2)
|
|
241
241
|
end
|
|
242
242
|
|
|
@@ -346,7 +346,12 @@ module Net
|
|
|
346
346
|
# Optimized version of write where the caller gives up ownership of string
|
|
347
347
|
# to the method. This way we can mutate the string.
|
|
348
348
|
def write_moved(string)
|
|
349
|
-
@content <<
|
|
349
|
+
@content <<
|
|
350
|
+
if string.frozen?
|
|
351
|
+
string.dup.force_encoding('BINARY')
|
|
352
|
+
else
|
|
353
|
+
string.force_encoding('BINARY')
|
|
354
|
+
end
|
|
350
355
|
self
|
|
351
356
|
end
|
|
352
357
|
|
data/lib/net/ssh/buffered_io.rb
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
require 'net/ssh/buffer'
|
|
2
2
|
require 'net/ssh/loggable'
|
|
3
3
|
|
|
4
|
-
module Net
|
|
4
|
+
module Net
|
|
5
5
|
module SSH
|
|
6
|
-
|
|
7
6
|
# This module is used to extend sockets and other IO objects, to allow
|
|
8
7
|
# them to be buffered for both read and write. This abstraction makes it
|
|
9
8
|
# quite easy to write a select-based event loop
|
|
@@ -48,7 +47,7 @@ module Net
|
|
|
48
47
|
# end
|
|
49
48
|
module BufferedIo
|
|
50
49
|
include Loggable
|
|
51
|
-
|
|
50
|
+
|
|
52
51
|
# Called when the #extend is called on an object, with this module as the
|
|
53
52
|
# argument. It ensures that the modules instance variables are all properly
|
|
54
53
|
# initialized.
|
|
@@ -56,7 +55,7 @@ module Net
|
|
|
56
55
|
# need to use __send__ because #send is overridden in Socket
|
|
57
56
|
object.__send__(:initialize_buffered_io)
|
|
58
57
|
end
|
|
59
|
-
|
|
58
|
+
|
|
60
59
|
# Tries to read up to +n+ bytes of data from the remote end, and appends
|
|
61
60
|
# the data to the input buffer. It returns the number of bytes read, or 0
|
|
62
61
|
# if no data was available to be read.
|
|
@@ -70,31 +69,31 @@ module Net
|
|
|
70
69
|
@input_errors << e
|
|
71
70
|
return 0
|
|
72
71
|
end
|
|
73
|
-
|
|
72
|
+
|
|
74
73
|
# Read up to +length+ bytes from the input buffer. If +length+ is nil,
|
|
75
74
|
# all available data is read from the buffer. (See #available.)
|
|
76
75
|
def read_available(length=nil)
|
|
77
76
|
input.read(length || available)
|
|
78
77
|
end
|
|
79
|
-
|
|
78
|
+
|
|
80
79
|
# Returns the number of bytes available to be read from the input buffer.
|
|
81
80
|
# (See #read_available.)
|
|
82
81
|
def available
|
|
83
82
|
input.available
|
|
84
83
|
end
|
|
85
|
-
|
|
84
|
+
|
|
86
85
|
# Enqueues data in the output buffer, to be written when #send_pending
|
|
87
86
|
# is called. Note that the data is _not_ sent immediately by this method!
|
|
88
87
|
def enqueue(data)
|
|
89
88
|
output.append(data)
|
|
90
89
|
end
|
|
91
|
-
|
|
90
|
+
|
|
92
91
|
# Returns +true+ if there is data waiting in the output buffer, and
|
|
93
92
|
# +false+ otherwise.
|
|
94
93
|
def pending_write?
|
|
95
94
|
output.length > 0
|
|
96
95
|
end
|
|
97
|
-
|
|
96
|
+
|
|
98
97
|
# Sends as much of the pending output as possible. Returns +true+ if any
|
|
99
98
|
# data was sent, and +false+ otherwise.
|
|
100
99
|
def send_pending
|
|
@@ -107,7 +106,7 @@ module Net
|
|
|
107
106
|
return false
|
|
108
107
|
end
|
|
109
108
|
end
|
|
110
|
-
|
|
109
|
+
|
|
111
110
|
# Calls #send_pending repeatedly, if necessary, blocking until the output
|
|
112
111
|
# buffer is empty.
|
|
113
112
|
def wait_for_pending_sends
|
|
@@ -115,31 +114,32 @@ module Net
|
|
|
115
114
|
while output.length > 0
|
|
116
115
|
result = IO.select(nil, [self]) or next
|
|
117
116
|
next unless result[1].any?
|
|
117
|
+
|
|
118
118
|
send_pending
|
|
119
119
|
end
|
|
120
120
|
end
|
|
121
|
-
|
|
121
|
+
|
|
122
122
|
public # these methods are primarily for use in tests
|
|
123
|
-
|
|
123
|
+
|
|
124
124
|
def write_buffer #:nodoc:
|
|
125
125
|
output.to_s
|
|
126
126
|
end
|
|
127
|
-
|
|
127
|
+
|
|
128
128
|
def read_buffer #:nodoc:
|
|
129
129
|
input.to_s
|
|
130
130
|
end
|
|
131
|
-
|
|
131
|
+
|
|
132
132
|
private
|
|
133
|
-
|
|
133
|
+
|
|
134
134
|
#--
|
|
135
135
|
# Can't use attr_reader here (after +private+) without incurring the
|
|
136
136
|
# wrath of "ruby -w". We hates it.
|
|
137
137
|
#++
|
|
138
|
-
|
|
138
|
+
|
|
139
139
|
def input; @input; end
|
|
140
140
|
|
|
141
141
|
def output; @output; end
|
|
142
|
-
|
|
142
|
+
|
|
143
143
|
# Initializes the intput and output buffers for this object. This method
|
|
144
144
|
# is called automatically when the module is mixed into an object via
|
|
145
145
|
# Object#extend (see Net::SSH::BufferedIo.extended), but must be called
|
|
@@ -181,7 +181,7 @@ module Net
|
|
|
181
181
|
end
|
|
182
182
|
end
|
|
183
183
|
end
|
|
184
|
-
|
|
184
|
+
|
|
185
185
|
def send_pending
|
|
186
186
|
begin
|
|
187
187
|
super
|
|
@@ -198,6 +198,5 @@ module Net
|
|
|
198
198
|
end
|
|
199
199
|
end
|
|
200
200
|
end
|
|
201
|
-
|
|
202
201
|
end
|
|
203
202
|
end
|
data/lib/net/ssh/config.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
module Net
|
|
2
2
|
module SSH
|
|
3
|
-
|
|
4
3
|
# The Net::SSH::Config class is used to parse OpenSSH configuration files,
|
|
5
4
|
# and translates that syntax into the configuration syntax that Net::SSH
|
|
6
5
|
# understands. This lets Net::SSH scripts read their configuration (to
|
|
@@ -34,7 +33,7 @@ module Net
|
|
|
34
33
|
# * ProxyJump => maps to the :proxy option
|
|
35
34
|
# * PubKeyAuthentication => maps to the :auth_methods option
|
|
36
35
|
# * RekeyLimit => :rekey_limit
|
|
37
|
-
# * StrictHostKeyChecking => :
|
|
36
|
+
# * StrictHostKeyChecking => :verify_host_key
|
|
38
37
|
# * User => :user
|
|
39
38
|
# * UserKnownHostsFile => :user_known_hosts_file
|
|
40
39
|
# * NumberOfPasswordPrompts => :number_of_password_prompts
|
|
@@ -186,17 +185,35 @@ module Net
|
|
|
186
185
|
# Filters default_files down to the files that are expandable.
|
|
187
186
|
def expandable_default_files
|
|
188
187
|
default_files.keep_if do |path|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
false
|
|
194
|
-
end
|
|
188
|
+
File.expand_path(path)
|
|
189
|
+
true
|
|
190
|
+
rescue ArgumentError
|
|
191
|
+
false
|
|
195
192
|
end
|
|
196
193
|
end
|
|
197
194
|
|
|
198
195
|
private
|
|
199
196
|
|
|
197
|
+
def translate_verify_host_key(value)
|
|
198
|
+
case value
|
|
199
|
+
when false
|
|
200
|
+
:never
|
|
201
|
+
when true
|
|
202
|
+
:always
|
|
203
|
+
when 'accept-new'
|
|
204
|
+
:accept_new
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def translate_keepalive(hash, value)
|
|
209
|
+
if value && value.to_i > 0
|
|
210
|
+
hash[:keepalive] = true
|
|
211
|
+
hash[:keepalive_interval] = value.to_i
|
|
212
|
+
else
|
|
213
|
+
hash[:keepalive] = false
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
200
217
|
TRANSLATE_CONFIG_KEY_RENAME_MAP = {
|
|
201
218
|
bindaddress: :bind_address,
|
|
202
219
|
compression: :compression,
|
|
@@ -211,13 +228,14 @@ module Net
|
|
|
211
228
|
identityfile: :keys,
|
|
212
229
|
fingerprinthash: :fingerprint_hash,
|
|
213
230
|
port: :port,
|
|
214
|
-
stricthostkeychecking: :strict_host_key_checking,
|
|
215
231
|
user: :user,
|
|
216
232
|
userknownhostsfile: :user_known_hosts_file,
|
|
217
233
|
checkhostip: :check_host_ip
|
|
218
234
|
}.freeze
|
|
219
235
|
def translate_config_key(hash, key, value, settings)
|
|
220
236
|
case key
|
|
237
|
+
when :stricthostkeychecking
|
|
238
|
+
hash[:verify_host_key] = translate_verify_host_key(value)
|
|
221
239
|
when :ciphers
|
|
222
240
|
hash[:encryption] = value.split(/,/)
|
|
223
241
|
when :hostbasedauthentication
|
|
@@ -235,12 +253,7 @@ module Net
|
|
|
235
253
|
when :serveralivecountmax
|
|
236
254
|
hash[:keepalive_maxcount] = value.to_i if value
|
|
237
255
|
when :serveraliveinterval
|
|
238
|
-
|
|
239
|
-
hash[:keepalive] = true
|
|
240
|
-
hash[:keepalive_interval] = value.to_i
|
|
241
|
-
else
|
|
242
|
-
hash[:keepalive] = false
|
|
243
|
-
end
|
|
256
|
+
translate_keepalive(hash, value)
|
|
244
257
|
when :passwordauthentication
|
|
245
258
|
if value
|
|
246
259
|
(hash[:auth_methods] << 'password').uniq!
|
|
@@ -302,7 +315,7 @@ module Net
|
|
|
302
315
|
# host names.
|
|
303
316
|
def pattern2regex(pattern)
|
|
304
317
|
tail = pattern
|
|
305
|
-
prefix =
|
|
318
|
+
prefix = String.new
|
|
306
319
|
while !tail.empty? do
|
|
307
320
|
head,sep,tail = tail.partition(/[\*\?]/)
|
|
308
321
|
prefix = prefix + Regexp.quote(head)
|
|
@@ -5,7 +5,6 @@ require 'net/ssh/connection/term'
|
|
|
5
5
|
module Net
|
|
6
6
|
module SSH
|
|
7
7
|
module Connection
|
|
8
|
-
|
|
9
8
|
# The channel abstraction. Multiple "channels" can be multiplexed onto a
|
|
10
9
|
# single SSH channel, each operating independently and seemingly in parallel.
|
|
11
10
|
# This class represents a single such channel. Most operations performed
|
|
@@ -55,55 +54,55 @@ module Net
|
|
|
55
54
|
class Channel
|
|
56
55
|
include Loggable
|
|
57
56
|
include Constants
|
|
58
|
-
|
|
57
|
+
|
|
59
58
|
# The local id for this channel, assigned by the Net::SSH::Connection::Session instance.
|
|
60
59
|
attr_reader :local_id
|
|
61
|
-
|
|
60
|
+
|
|
62
61
|
# The remote id for this channel, assigned by the remote host.
|
|
63
62
|
attr_reader :remote_id
|
|
64
|
-
|
|
63
|
+
|
|
65
64
|
# The type of this channel, usually "session".
|
|
66
65
|
attr_reader :type
|
|
67
|
-
|
|
66
|
+
|
|
68
67
|
# The underlying Net::SSH::Connection::Session instance that supports this channel.
|
|
69
68
|
attr_reader :connection
|
|
70
|
-
|
|
69
|
+
|
|
71
70
|
# The maximum packet size that the local host can receive.
|
|
72
71
|
attr_reader :local_maximum_packet_size
|
|
73
|
-
|
|
72
|
+
|
|
74
73
|
# The maximum amount of data that the local end of this channel can
|
|
75
74
|
# receive. This is a total, not per-packet.
|
|
76
75
|
attr_reader :local_maximum_window_size
|
|
77
|
-
|
|
76
|
+
|
|
78
77
|
# The maximum packet size that the remote host can receive.
|
|
79
78
|
attr_reader :remote_maximum_packet_size
|
|
80
|
-
|
|
79
|
+
|
|
81
80
|
# The maximum amount of data that the remote end of this channel can
|
|
82
81
|
# receive. This is a total, not per-packet.
|
|
83
82
|
attr_reader :remote_maximum_window_size
|
|
84
|
-
|
|
83
|
+
|
|
85
84
|
# This is the remaining window size on the local end of this channel. When
|
|
86
85
|
# this reaches zero, no more data can be received.
|
|
87
86
|
attr_reader :local_window_size
|
|
88
|
-
|
|
87
|
+
|
|
89
88
|
# This is the remaining window size on the remote end of this channel. When
|
|
90
89
|
# this reaches zero, no more data can be sent.
|
|
91
90
|
attr_reader :remote_window_size
|
|
92
|
-
|
|
91
|
+
|
|
93
92
|
# A hash of properties for this channel. These can be used to store state
|
|
94
93
|
# information about this channel. See also #[] and #[]=.
|
|
95
94
|
attr_reader :properties
|
|
96
|
-
|
|
95
|
+
|
|
97
96
|
# The output buffer for this channel. Data written to the channel is
|
|
98
97
|
# enqueued here, to be written as CHANNEL_DATA packets during each pass of
|
|
99
98
|
# the event loop. See Connection::Session#process and #enqueue_pending_output.
|
|
100
99
|
attr_reader :output #:nodoc:
|
|
101
|
-
|
|
100
|
+
|
|
102
101
|
# The list of pending requests. Each time a request is sent which requires
|
|
103
102
|
# a reply, the corresponding callback is pushed onto this queue. As responses
|
|
104
103
|
# arrive, they are shifted off the front and handled.
|
|
105
104
|
attr_reader :pending_requests #:nodoc:
|
|
106
|
-
|
|
105
|
+
|
|
107
106
|
# Instantiates a new channel on the given connection, of the given type,
|
|
108
107
|
# and with the given id. If a block is given, it will be remembered until
|
|
109
108
|
# the channel is confirmed open by the server, and will be invoked at
|
|
@@ -112,36 +111,36 @@ module Net
|
|
|
112
111
|
# This also sets the default maximum packet size and maximum window size.
|
|
113
112
|
def initialize(connection, type, local_id, max_pkt_size = 0x8000, max_win_size = 0x20000, &on_confirm_open)
|
|
114
113
|
self.logger = connection.logger
|
|
115
|
-
|
|
114
|
+
|
|
116
115
|
@connection = connection
|
|
117
116
|
@type = type
|
|
118
117
|
@local_id = local_id
|
|
119
|
-
|
|
118
|
+
|
|
120
119
|
@local_maximum_packet_size = max_pkt_size
|
|
121
120
|
@local_window_size = @local_maximum_window_size = max_win_size
|
|
122
|
-
|
|
121
|
+
|
|
123
122
|
@on_confirm_open = on_confirm_open
|
|
124
|
-
|
|
123
|
+
|
|
125
124
|
@output = Buffer.new
|
|
126
|
-
|
|
125
|
+
|
|
127
126
|
@properties = {}
|
|
128
|
-
|
|
127
|
+
|
|
129
128
|
@pending_requests = []
|
|
130
129
|
@on_open_failed = @on_data = @on_extended_data = @on_process = @on_close = @on_eof = nil
|
|
131
130
|
@on_request = {}
|
|
132
131
|
@closing = @eof = @sent_eof = @local_closed = @remote_closed = false
|
|
133
132
|
end
|
|
134
|
-
|
|
133
|
+
|
|
135
134
|
# A shortcut for accessing properties of the channel (see #properties).
|
|
136
135
|
def [](name)
|
|
137
136
|
@properties[name]
|
|
138
137
|
end
|
|
139
|
-
|
|
138
|
+
|
|
140
139
|
# A shortcut for setting properties of the channel (see #properties).
|
|
141
140
|
def []=(name, value)
|
|
142
141
|
@properties[name] = value
|
|
143
142
|
end
|
|
144
|
-
|
|
143
|
+
|
|
145
144
|
# Syntactic sugar for executing a command. Sends a channel request asking
|
|
146
145
|
# that the given command be invoked. If the block is given, it will be
|
|
147
146
|
# called when the server responds. The first parameter will be the
|
|
@@ -161,7 +160,7 @@ module Net
|
|
|
161
160
|
def exec(command, &block)
|
|
162
161
|
send_channel_request("exec", :string, command, &block)
|
|
163
162
|
end
|
|
164
|
-
|
|
163
|
+
|
|
165
164
|
# Syntactic sugar for requesting that a subsystem be started. Subsystems
|
|
166
165
|
# are a way for other protocols (like SFTP) to be run, using SSH as
|
|
167
166
|
# the transport. Generally, you'll never need to call this directly unless
|
|
@@ -178,7 +177,7 @@ module Net
|
|
|
178
177
|
def subsystem(subsystem, &block)
|
|
179
178
|
send_channel_request("subsystem", :string, subsystem, &block)
|
|
180
179
|
end
|
|
181
|
-
|
|
180
|
+
|
|
182
181
|
# Syntactic sugar for setting an environment variable in the remote
|
|
183
182
|
# process' environment. Note that for security reasons, the server may
|
|
184
183
|
# refuse to set certain environment variables, or all, at the server's
|
|
@@ -190,7 +189,7 @@ module Net
|
|
|
190
189
|
def env(variable_name, variable_value, &block)
|
|
191
190
|
send_channel_request("env", :string, variable_name, :string, variable_value, &block)
|
|
192
191
|
end
|
|
193
|
-
|
|
192
|
+
|
|
194
193
|
# A hash of the valid PTY options (see #request_pty).
|
|
195
194
|
VALID_PTY_OPTIONS = { term: "xterm",
|
|
196
195
|
chars_wide: 80,
|
|
@@ -198,7 +197,7 @@ module Net
|
|
|
198
197
|
pixels_wide: 640,
|
|
199
198
|
pixels_high: 480,
|
|
200
199
|
modes: {} }
|
|
201
|
-
|
|
200
|
+
|
|
202
201
|
# Requests that a pseudo-tty (or "pty") be made available for this channel.
|
|
203
202
|
# This is useful when you want to invoke and interact with some kind of
|
|
204
203
|
# screen-based program (e.g., vim, or some menuing system).
|
|
@@ -221,21 +220,21 @@ module Net
|
|
|
221
220
|
def request_pty(opts={}, &block)
|
|
222
221
|
extra = opts.keys - VALID_PTY_OPTIONS.keys
|
|
223
222
|
raise ArgumentError, "invalid option(s) to request_pty: #{extra.inspect}" if extra.any?
|
|
224
|
-
|
|
223
|
+
|
|
225
224
|
opts = VALID_PTY_OPTIONS.merge(opts)
|
|
226
|
-
|
|
225
|
+
|
|
227
226
|
modes = opts[:modes].inject(Buffer.new) do |memo, (mode, data)|
|
|
228
227
|
memo.write_byte(mode).write_long(data)
|
|
229
228
|
end
|
|
230
229
|
# mark the end of the mode opcode list with a 0 byte
|
|
231
230
|
modes.write_byte(0)
|
|
232
|
-
|
|
231
|
+
|
|
233
232
|
send_channel_request("pty-req", :string, opts[:term],
|
|
234
233
|
:long, opts[:chars_wide], :long, opts[:chars_high],
|
|
235
234
|
:long, opts[:pixels_wide], :long, opts[:pixels_high],
|
|
236
235
|
:string, modes.to_s, &block)
|
|
237
236
|
end
|
|
238
|
-
|
|
237
|
+
|
|
239
238
|
# Sends data to the channel's remote endpoint. This usually has the
|
|
240
239
|
# effect of sending the given string to the remote process' stdin stream.
|
|
241
240
|
# Note that it does not immediately send the data across the channel,
|
|
@@ -251,9 +250,10 @@ module Net
|
|
|
251
250
|
# channel.send_data("the password\n")
|
|
252
251
|
def send_data(data)
|
|
253
252
|
raise EOFError, "cannot send data if channel has declared eof" if eof?
|
|
253
|
+
|
|
254
254
|
output.append(data.to_s)
|
|
255
255
|
end
|
|
256
|
-
|
|
256
|
+
|
|
257
257
|
# Returns true if the channel exists in the channel list of the session,
|
|
258
258
|
# and false otherwise. This can be used to determine whether a channel has
|
|
259
259
|
# been closed or not.
|
|
@@ -262,7 +262,7 @@ module Net
|
|
|
262
262
|
def active?
|
|
263
263
|
connection.channels.key?(local_id)
|
|
264
264
|
end
|
|
265
|
-
|
|
265
|
+
|
|
266
266
|
# Runs the SSH event loop until the channel is no longer active. This is
|
|
267
267
|
# handy for blocking while you wait for some channel to finish.
|
|
268
268
|
#
|
|
@@ -271,7 +271,7 @@ module Net
|
|
|
271
271
|
def wait
|
|
272
272
|
connection.loop { active? }
|
|
273
273
|
end
|
|
274
|
-
|
|
274
|
+
|
|
275
275
|
# True if close() has been called; NOTE: if the channel has data waiting to
|
|
276
276
|
# be sent then the channel will close after all the data is sent. See
|
|
277
277
|
# closed?() to determine if we have actually sent CHANNEL_CLOSE to server.
|
|
@@ -280,61 +280,63 @@ module Net
|
|
|
280
280
|
def closing?
|
|
281
281
|
@closing
|
|
282
282
|
end
|
|
283
|
-
|
|
283
|
+
|
|
284
284
|
# True if we have sent CHANNEL_CLOSE to the remote server.
|
|
285
285
|
def local_closed?
|
|
286
286
|
@local_closed
|
|
287
287
|
end
|
|
288
|
-
|
|
288
|
+
|
|
289
289
|
def remote_closed?
|
|
290
290
|
@remote_closed
|
|
291
291
|
end
|
|
292
|
-
|
|
292
|
+
|
|
293
293
|
def remote_closed!
|
|
294
294
|
@remote_closed = true
|
|
295
295
|
end
|
|
296
|
-
|
|
296
|
+
|
|
297
297
|
# Requests that the channel be closed. It only marks the channel to be closed
|
|
298
298
|
# the CHANNEL_CLOSE message will be sent from event loop
|
|
299
299
|
def close
|
|
300
300
|
return if @closing
|
|
301
|
+
|
|
301
302
|
@closing = true
|
|
302
303
|
end
|
|
303
|
-
|
|
304
|
+
|
|
304
305
|
# Returns true if the local end of the channel has declared that no more
|
|
305
306
|
# data is forthcoming (see #eof!). Trying to send data via #send_data when
|
|
306
307
|
# this is true will result in an exception being raised.
|
|
307
308
|
def eof?
|
|
308
309
|
@eof
|
|
309
310
|
end
|
|
310
|
-
|
|
311
|
+
|
|
311
312
|
# Tells the remote end of the channel that no more data is forthcoming
|
|
312
313
|
# from this end of the channel. The remote end may still send data.
|
|
313
314
|
# The CHANNEL_EOF packet will be sent once the output buffer is empty.
|
|
314
315
|
def eof!
|
|
315
316
|
return if eof?
|
|
317
|
+
|
|
316
318
|
@eof = true
|
|
317
319
|
end
|
|
318
|
-
|
|
320
|
+
|
|
319
321
|
# If an #on_process handler has been set up, this will cause it to be
|
|
320
322
|
# invoked (passing the channel itself as an argument). It also causes all
|
|
321
323
|
# pending output to be enqueued as CHANNEL_DATA packets (see #enqueue_pending_output).
|
|
322
324
|
def process
|
|
323
325
|
@on_process.call(self) if @on_process
|
|
324
326
|
enqueue_pending_output
|
|
325
|
-
|
|
327
|
+
|
|
326
328
|
if @eof and not @sent_eof and output.empty? and remote_id and not @local_closed
|
|
327
329
|
connection.send_message(Buffer.from(:byte, CHANNEL_EOF, :long, remote_id))
|
|
328
330
|
@sent_eof = true
|
|
329
331
|
end
|
|
330
|
-
|
|
332
|
+
|
|
331
333
|
if @closing and not @local_closed and output.empty? and remote_id
|
|
332
334
|
connection.send_message(Buffer.from(:byte, CHANNEL_CLOSE, :long, remote_id))
|
|
333
335
|
@local_closed = true
|
|
334
336
|
connection.cleanup_channel(self)
|
|
335
337
|
end
|
|
336
338
|
end
|
|
337
|
-
|
|
339
|
+
|
|
338
340
|
# Registers a callback to be invoked when data packets are received by the
|
|
339
341
|
# channel. The callback is called with the channel as the first argument,
|
|
340
342
|
# and the data as the second.
|
|
@@ -349,7 +351,7 @@ module Net
|
|
|
349
351
|
old, @on_data = @on_data, block
|
|
350
352
|
old
|
|
351
353
|
end
|
|
352
|
-
|
|
354
|
+
|
|
353
355
|
# Registers a callback to be invoked when extended data packets are received
|
|
354
356
|
# by the channel. The callback is called with the channel as the first
|
|
355
357
|
# argument, the data type (as an integer) as the second, and the data as
|
|
@@ -364,7 +366,7 @@ module Net
|
|
|
364
366
|
old, @on_extended_data = @on_extended_data, block
|
|
365
367
|
old
|
|
366
368
|
end
|
|
367
|
-
|
|
369
|
+
|
|
368
370
|
# Registers a callback to be invoked for each pass of the event loop for
|
|
369
371
|
# this channel. There are no guarantees on timeliness in the event loop,
|
|
370
372
|
# but it will be called roughly once for each packet received by the
|
|
@@ -391,7 +393,7 @@ module Net
|
|
|
391
393
|
old, @on_process = @on_process, block
|
|
392
394
|
old
|
|
393
395
|
end
|
|
394
|
-
|
|
396
|
+
|
|
395
397
|
# Registers a callback to be invoked when the server acknowledges that a
|
|
396
398
|
# channel is closed. This is invoked with the channel as the sole argument.
|
|
397
399
|
#
|
|
@@ -402,7 +404,7 @@ module Net
|
|
|
402
404
|
old, @on_close = @on_close, block
|
|
403
405
|
old
|
|
404
406
|
end
|
|
405
|
-
|
|
407
|
+
|
|
406
408
|
# Registers a callback to be invoked when the server indicates that no more
|
|
407
409
|
# data will be sent to the channel (although the channel can still send
|
|
408
410
|
# data to the server). The channel is the sole argument to the callback.
|
|
@@ -414,7 +416,7 @@ module Net
|
|
|
414
416
|
old, @on_eof = @on_eof, block
|
|
415
417
|
old
|
|
416
418
|
end
|
|
417
|
-
|
|
419
|
+
|
|
418
420
|
# Registers a callback to be invoked when the server was unable to open
|
|
419
421
|
# the requested channel. The channel itself will be passed to the block,
|
|
420
422
|
# along with the integer "reason code" for the failure, and a textual
|
|
@@ -429,7 +431,7 @@ module Net
|
|
|
429
431
|
old, @on_open_failed = @on_open_failed, block
|
|
430
432
|
old
|
|
431
433
|
end
|
|
432
|
-
|
|
434
|
+
|
|
433
435
|
# Registers a callback to be invoked when a channel request of the given
|
|
434
436
|
# type is received. The callback will receive the channel as the first
|
|
435
437
|
# argument, and the associated (unparsed) data as the second. The data
|
|
@@ -460,7 +462,7 @@ module Net
|
|
|
460
462
|
old, @on_request[type] = @on_request[type], block
|
|
461
463
|
old
|
|
462
464
|
end
|
|
463
|
-
|
|
465
|
+
|
|
464
466
|
# Sends a new channel request with the given name. The extra +data+
|
|
465
467
|
# parameter must either be empty, or consist of an even number of
|
|
466
468
|
# arguments. See Net::SSH::Buffer.from for a description of their format.
|
|
@@ -486,15 +488,16 @@ module Net
|
|
|
486
488
|
def send_channel_request(request_name, *data, &callback)
|
|
487
489
|
info { "sending channel request #{request_name.inspect}" }
|
|
488
490
|
fail "Channel open not yet confirmed, please call send_channel_request(or exec) from block of open_channel" unless remote_id
|
|
491
|
+
|
|
489
492
|
msg = Buffer.from(:byte, CHANNEL_REQUEST,
|
|
490
493
|
:long, remote_id, :string, request_name,
|
|
491
494
|
:bool, !callback.nil?, *data)
|
|
492
495
|
connection.send_message(msg)
|
|
493
496
|
pending_requests << callback if callback
|
|
494
497
|
end
|
|
495
|
-
|
|
498
|
+
|
|
496
499
|
public # these methods are public, but for Net::SSH internal use only
|
|
497
|
-
|
|
500
|
+
|
|
498
501
|
# Enqueues pending output at the connection as CHANNEL_DATA packets. This
|
|
499
502
|
# does nothing if the channel has not yet been confirmed open (see
|
|
500
503
|
# #do_open_confirmation). This is called automatically by #process, which
|
|
@@ -502,12 +505,12 @@ module Net
|
|
|
502
505
|
# generally not need to invoke it directly.
|
|
503
506
|
def enqueue_pending_output #:nodoc:
|
|
504
507
|
return unless remote_id
|
|
505
|
-
|
|
508
|
+
|
|
506
509
|
while output.length > 0
|
|
507
510
|
length = output.length
|
|
508
511
|
length = remote_window_size if length > remote_window_size
|
|
509
512
|
length = remote_maximum_packet_size if length > remote_maximum_packet_size
|
|
510
|
-
|
|
513
|
+
|
|
511
514
|
if length > 0
|
|
512
515
|
connection.send_message(Buffer.from(:byte, CHANNEL_DATA, :long, remote_id, :string, output.read(length)))
|
|
513
516
|
output.consume!
|
|
@@ -517,7 +520,7 @@ module Net
|
|
|
517
520
|
end
|
|
518
521
|
end
|
|
519
522
|
end
|
|
520
|
-
|
|
523
|
+
|
|
521
524
|
# Invoked when the server confirms that a channel has been opened.
|
|
522
525
|
# The remote_id is the id of the channel as assigned by the remote host,
|
|
523
526
|
# and max_window and max_packet are the maximum window and maximum
|
|
@@ -533,7 +536,7 @@ module Net
|
|
|
533
536
|
set_remote_env(connection.options[:set_env]) if connection.options[:set_env]
|
|
534
537
|
@on_confirm_open.call(self) if @on_confirm_open
|
|
535
538
|
end
|
|
536
|
-
|
|
539
|
+
|
|
537
540
|
# Invoked when the server failed to open the channel. If an #on_open_failed
|
|
538
541
|
# callback was specified, it will be invoked with the channel, reason code,
|
|
539
542
|
# and description as arguments. Otherwise, a ChannelOpenFailed exception
|
|
@@ -545,7 +548,7 @@ module Net
|
|
|
545
548
|
raise ChannelOpenFailed.new(reason_code, description)
|
|
546
549
|
end
|
|
547
550
|
end
|
|
548
|
-
|
|
551
|
+
|
|
549
552
|
# Invoked when the server sends a CHANNEL_WINDOW_ADJUST packet, and
|
|
550
553
|
# causes the remote window size to be adjusted upwards by the given
|
|
551
554
|
# number of bytes. This has the effect of allowing more data to be sent
|
|
@@ -554,7 +557,7 @@ module Net
|
|
|
554
557
|
@remote_maximum_window_size += bytes
|
|
555
558
|
@remote_window_size += bytes
|
|
556
559
|
end
|
|
557
|
-
|
|
560
|
+
|
|
558
561
|
# Invoked when the server sends a channel request. If any #on_request
|
|
559
562
|
# callback has been registered for the specific type of this request,
|
|
560
563
|
# it is invoked. If +want_reply+ is true, a packet will be sent of
|
|
@@ -565,20 +568,20 @@ module Net
|
|
|
565
568
|
# request-specific data as the second.
|
|
566
569
|
def do_request(request, want_reply, data) #:nodoc:
|
|
567
570
|
result = true
|
|
568
|
-
|
|
571
|
+
|
|
569
572
|
begin
|
|
570
573
|
callback = @on_request[request] or raise ChannelRequestFailed
|
|
571
574
|
callback.call(self, data)
|
|
572
575
|
rescue ChannelRequestFailed
|
|
573
576
|
result = false
|
|
574
577
|
end
|
|
575
|
-
|
|
578
|
+
|
|
576
579
|
if want_reply
|
|
577
580
|
msg = Buffer.from(:byte, result ? CHANNEL_SUCCESS : CHANNEL_FAILURE, :long, remote_id)
|
|
578
581
|
connection.send_message(msg)
|
|
579
582
|
end
|
|
580
583
|
end
|
|
581
|
-
|
|
584
|
+
|
|
582
585
|
# Invokes the #on_data callback when the server sends data to the
|
|
583
586
|
# channel. This will reduce the available window size on the local end,
|
|
584
587
|
# but does not actually throttle requests that come in illegally when
|
|
@@ -588,7 +591,7 @@ module Net
|
|
|
588
591
|
update_local_window_size(data.length)
|
|
589
592
|
@on_data.call(self, data) if @on_data
|
|
590
593
|
end
|
|
591
|
-
|
|
594
|
+
|
|
592
595
|
# Invokes the #on_extended_data callback when the server sends
|
|
593
596
|
# extended data to the channel. This will reduce the available window
|
|
594
597
|
# size on the local end. The callback is invoked with the channel,
|
|
@@ -597,20 +600,20 @@ module Net
|
|
|
597
600
|
update_local_window_size(data.length)
|
|
598
601
|
@on_extended_data.call(self, type, data) if @on_extended_data
|
|
599
602
|
end
|
|
600
|
-
|
|
603
|
+
|
|
601
604
|
# Invokes the #on_eof callback when the server indicates that no
|
|
602
605
|
# further data is forthcoming. The callback is invoked with the channel
|
|
603
606
|
# as the argument.
|
|
604
607
|
def do_eof
|
|
605
608
|
@on_eof.call(self) if @on_eof
|
|
606
609
|
end
|
|
607
|
-
|
|
610
|
+
|
|
608
611
|
# Invokes the #on_close callback when the server closes a channel.
|
|
609
612
|
# The channel is the only argument.
|
|
610
613
|
def do_close
|
|
611
614
|
@on_close.call(self) if @on_close
|
|
612
615
|
end
|
|
613
|
-
|
|
616
|
+
|
|
614
617
|
# Invokes the next pending request callback with +false+ as the second
|
|
615
618
|
# argument.
|
|
616
619
|
def do_failure
|
|
@@ -620,7 +623,7 @@ module Net
|
|
|
620
623
|
error { "channel failure received with no pending request to handle it (bug?)" }
|
|
621
624
|
end
|
|
622
625
|
end
|
|
623
|
-
|
|
626
|
+
|
|
624
627
|
# Invokes the next pending request callback with +true+ as the second
|
|
625
628
|
# argument.
|
|
626
629
|
def do_success
|
|
@@ -687,7 +690,6 @@ module Net
|
|
|
687
690
|
env.each { |key, value| self.env(key, value) }
|
|
688
691
|
end
|
|
689
692
|
end
|
|
690
|
-
|
|
691
693
|
end
|
|
692
694
|
end
|
|
693
695
|
end
|