net-ssh 2.9.4 → 2.10.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.travis.yml +11 -4
- data/CHANGES.txt +15 -5
- data/README.rdoc +1 -1
- data/Rakefile +12 -5
- data/lib/net/ssh.rb +16 -1
- data/lib/net/ssh/authentication/key_manager.rb +20 -11
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +11 -4
- data/lib/net/ssh/authentication/methods/password.rb +3 -1
- data/lib/net/ssh/authentication/pageant.rb +32 -12
- data/lib/net/ssh/connection/channel.rb +7 -26
- data/lib/net/ssh/connection/session.rb +2 -11
- data/lib/net/ssh/proxy/command.rb +14 -3
- data/lib/net/ssh/ruby_compat.rb +0 -5
- data/lib/net/ssh/transport/algorithms.rb +3 -4
- data/lib/net/ssh/transport/cipher_factory.rb +0 -1
- data/lib/net/ssh/transport/session.rb +8 -7
- data/lib/net/ssh/version.rb +4 -4
- data/net-ssh-public_cert.pem +15 -15
- data/net-ssh.gemspec +9 -5
- data/setup.rb +1 -1
- data/test/README.txt +6 -13
- data/test/authentication/methods/test_keyboard_interactive.rb +21 -0
- data/test/authentication/test_key_manager.rb +5 -1
- data/test/connection/test_channel.rb +0 -3
- data/test/connection/test_session.rb +8 -17
- data/test/integration/README.txt +19 -0
- data/test/integration/Vagrantfile +12 -0
- data/test/integration/common.rb +57 -0
- data/test/integration/playbook.yml +46 -0
- data/test/integration/test_id_rsa_keys.rb +78 -0
- data/test/start/test_options.rb +8 -1
- data/test/test_all.rb +1 -0
- data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +5 -1
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +5 -1
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +2 -17
- data/test/transport/test_algorithms.rb +21 -17
- data/test/transport/test_session.rb +1 -1
- metadata +24 -20
- metadata.gz.sig +0 -0
- data/Rudyfile +0 -96
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 99ac97b623723117ba47a0785cf3dc7d2e1ae594
|
4
|
+
data.tar.gz: 705651920fb196430521248ef4d457a955814ac6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e6a3403271ad3a629769a30b99a9e4802f918444d0c3b97ef8f2df955ae9b2aeac2eaf0c64454227c4d74ac375d3ccf0e60ee7e19518cf1e63f424dd22d3dceb
|
7
|
+
data.tar.gz: f84cae92e328113fa58bfd19e0e828412fe1bdce7bc0fa2cdca254b7c25562c0efcd1a9de5987de3be6180f5c64583baee4f560b748f65d37eabd0760529eadf
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/.travis.yml
CHANGED
@@ -1,10 +1,17 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
-
|
4
|
-
-
|
3
|
+
- 1.9.3
|
4
|
+
- 2.0.0
|
5
|
+
- 2.1.0
|
6
|
+
- 2.2.0
|
7
|
+
- jruby-head
|
8
|
+
- jruby-19mode
|
9
|
+
- rbx-2
|
5
10
|
|
6
|
-
|
7
|
-
install: gem install jeweler test-unit mocha
|
11
|
+
install: gem install test-unit mocha
|
8
12
|
|
9
13
|
script: rake test
|
10
14
|
|
15
|
+
matrix:
|
16
|
+
allow_failures:
|
17
|
+
- rvm: jruby-head
|
data/CHANGES.txt
CHANGED
@@ -1,10 +1,20 @@
|
|
1
|
-
=== 2.
|
1
|
+
=== 2.10.0-?
|
2
2
|
|
3
|
-
*
|
3
|
+
* Fix could not parse PKey error. [Andrey Voronkov]
|
4
|
+
* Workaround for threading issue in MRI + singleton method declaration [Matt Brictson]
|
5
|
+
* Configuration change: we no longer append all supported algorithms, this is so you can exclude insecure algorithms. If you want to use the old behaviour specify append_all_supported_algorithms => true [voidus, mfazekas]
|
6
|
+
* New configuration option: :non_interactive => true in case you prefer an authmethod to fail rather than prompt. [mfazekas]
|
7
|
+
* Configuration change: password will now ask for password up to the :number_of_password_prompts times. If you want the
|
8
|
+
2.9.1 behaviour of never asking password please set number_of_password_prompts to 0.
|
4
9
|
|
5
|
-
|
10
|
+
=== 2.9.4-beta1
|
11
|
+
|
12
|
+
* Use sysread and syswrite on Windows instead of read_nonblock and write [marc-etienne]
|
13
|
+
* Windows/peagant: use fiddle on ruby 2.2+/windows [Charlie Savage]
|
14
|
+
* Check if ssh key is a file [kiela]
|
15
|
+
|
16
|
+
=== 2.9.3
|
6
17
|
|
7
|
-
=== 2.9.2
|
8
18
|
=== 2.9.2-rc3
|
9
19
|
|
10
20
|
* Remove advertised algorithms that were not working (curve25519-sha256@libssh.org) [mfazekas]
|
@@ -21,7 +31,7 @@
|
|
21
31
|
|
22
32
|
* Remove advertised algorithms that were not working (ssh-rsa-cert-* *ed25519 acm*-gcm@openssh.com) [mfazekas]
|
23
33
|
* Unkown algorithms now ignored instead of failed [mfazekas]
|
24
|
-
* Asks for password with password auth (up to number_of_password_prompts) [mfazekas]
|
34
|
+
* Configuration change: Asks for password with password auth (up to number_of_password_prompts) [mfazekas]
|
25
35
|
* Removed warnings [amatsuda]
|
26
36
|
|
27
37
|
=== 2.9.1 / 13 May 2014
|
data/README.rdoc
CHANGED
@@ -112,7 +112,7 @@ If you don't add the public key, you'll see an error like "Couldn't verify data
|
|
112
112
|
|
113
113
|
== RUBY 1.8 SUPPORT
|
114
114
|
|
115
|
-
net-ssh supports Ruby 1.8.x up until the 2.5.1 release.
|
115
|
+
net-ssh supports Ruby 1.8.x up until the 2.5.1 release. Current version requires ruby 1.9 or later.
|
116
116
|
|
117
117
|
== JRUBY 1.6
|
118
118
|
|
data/Rakefile
CHANGED
@@ -8,6 +8,7 @@
|
|
8
8
|
require "rubygems"
|
9
9
|
require "rake"
|
10
10
|
require "rake/clean"
|
11
|
+
if RUBY_VERSION >= '1.9.0'
|
11
12
|
require "rdoc/task"
|
12
13
|
|
13
14
|
task :default => ["build"]
|
@@ -55,11 +56,6 @@ rescue LoadError
|
|
55
56
|
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
56
57
|
end
|
57
58
|
|
58
|
-
require 'rake/testtask'
|
59
|
-
Rake::TestTask.new do |t|
|
60
|
-
t.libs = ["lib", "test"]
|
61
|
-
end
|
62
|
-
|
63
59
|
extra_files = %w[LICENSE.txt THANKS.txt CHANGES.txt ]
|
64
60
|
RDoc::Task.new do |rdoc|
|
65
61
|
rdoc.rdoc_dir = "rdoc"
|
@@ -73,3 +69,14 @@ RDoc::Task.new do |rdoc|
|
|
73
69
|
rdoc.rdoc_files.include(file) if File.exists?(file)
|
74
70
|
}
|
75
71
|
end
|
72
|
+
end
|
73
|
+
|
74
|
+
require 'rake/testtask'
|
75
|
+
Rake::TestTask.new do |t|
|
76
|
+
t.libs = ["lib", "test"]
|
77
|
+
end
|
78
|
+
|
79
|
+
Rake::TestTask.new(:'integration-test') do |t|
|
80
|
+
t.libs = ["lib", "test/integration"]
|
81
|
+
t.pattern = 'test/integration/test_*.rb'
|
82
|
+
end
|
data/lib/net/ssh.rb
CHANGED
@@ -68,7 +68,8 @@ module Net
|
|
68
68
|
:rekey_blocks_limit,:rekey_limit, :rekey_packet_limit, :timeout, :verbose,
|
69
69
|
:global_known_hosts_file, :user_known_hosts_file, :host_key_alias,
|
70
70
|
:host_name, :user, :properties, :passphrase, :keys_only, :max_pkt_size,
|
71
|
-
:max_win_size, :send_env, :use_agent, :number_of_password_prompts
|
71
|
+
:max_win_size, :send_env, :use_agent, :number_of_password_prompts,
|
72
|
+
:append_supported_algorithms, :non_interactive
|
72
73
|
]
|
73
74
|
|
74
75
|
# The standard means of starting a new SSH connection. When used with a
|
@@ -173,10 +174,19 @@ module Net
|
|
173
174
|
# Defaults to %w(~/.ssh/known_hosts ~/.ssh/known_hosts2).
|
174
175
|
# * :use_agent => Set false to disable the use of ssh-agent. Defaults to
|
175
176
|
# true
|
177
|
+
# * :non_interactive => set to true if your app is non interactive and prefers
|
178
|
+
# authentication failure vs password prompt
|
176
179
|
# * :verbose => how verbose to be (Logger verbosity constants, Logger::DEBUG
|
177
180
|
# is very verbose, Logger::FATAL is all but silent). Logger::FATAL is the
|
178
181
|
# default. The symbols :debug, :info, :warn, :error, and :fatal are also
|
179
182
|
# supported and are translated to the corresponding Logger constant.
|
183
|
+
# * :append_all_supported_algorithms => set to +true+ to append all supported
|
184
|
+
# algorithms by net-ssh. Was the default behaviour until 2.10
|
185
|
+
# * :number_of_password_prompts => Number of prompts for the password
|
186
|
+
# authentication method defaults to 3 set to 0 to disable prompt for
|
187
|
+
# password auth method
|
188
|
+
# * :non_interactive => non interactive applications should set it to true
|
189
|
+
# to prefer failing a password/etc auth methods vs asking for password
|
180
190
|
def self.start(host, user, options={}, &block)
|
181
191
|
invalid_options = options.keys - VALID_OPTIONS
|
182
192
|
if invalid_options.any?
|
@@ -192,6 +202,11 @@ module Net
|
|
192
202
|
options[:logger].level = Logger::FATAL
|
193
203
|
end
|
194
204
|
|
205
|
+
if options[:non_interactive]
|
206
|
+
options[:number_of_password_prompts] = 0
|
207
|
+
options[:passphrase] = false
|
208
|
+
end
|
209
|
+
|
195
210
|
if options[:verbose]
|
196
211
|
options[:logger].level = case options[:verbose]
|
197
212
|
when Fixnum then options[:verbose]
|
@@ -187,15 +187,24 @@ module Net
|
|
187
187
|
# Prepares identities from user key_files for loading, preserving their order and sources.
|
188
188
|
def prepare_identities_from_files
|
189
189
|
key_files.map do |file|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
190
|
+
if readable_file?(file)
|
191
|
+
identity = {}
|
192
|
+
public_key_file = file + ".pub"
|
193
|
+
if readable_file?(public_key_file)
|
194
|
+
identity[:load_from] = :pubkey_file
|
195
|
+
identity[:pubkey_file] = public_key_file
|
196
|
+
else
|
197
|
+
identity[:load_from] = :privkey_file
|
198
|
+
end
|
199
|
+
identity.merge(privkey_file: file)
|
195
200
|
end
|
196
201
|
end.compact
|
197
202
|
end
|
198
203
|
|
204
|
+
def readable_file?(path)
|
205
|
+
File.file?(path) && File.readable?(path)
|
206
|
+
end
|
207
|
+
|
199
208
|
# Prepared identities from user key_data, preserving their order and sources.
|
200
209
|
def prepare_identities_from_data
|
201
210
|
key_data.map do |data|
|
@@ -209,12 +218,12 @@ module Net
|
|
209
218
|
begin
|
210
219
|
case identity[:load_from]
|
211
220
|
when :pubkey_file
|
212
|
-
key = KeyFactory.load_public_key(identity[:
|
213
|
-
{ :public_key => key, :from => :file, :file => identity[:
|
221
|
+
key = KeyFactory.load_public_key(identity[:pubkey_file])
|
222
|
+
{ :public_key => key, :from => :file, :file => identity[:privkey_file] }
|
214
223
|
when :privkey_file
|
215
|
-
private_key = KeyFactory.load_private_key(identity[:
|
224
|
+
private_key = KeyFactory.load_private_key(identity[:privkey_file], options[:passphrase], ask_passphrase)
|
216
225
|
key = private_key.send(:public_key)
|
217
|
-
{ :public_key => key, :from => :file, :file => identity[:
|
226
|
+
{ :public_key => key, :from => :file, :file => identity[:privkey_file], :key => private_key }
|
218
227
|
when :data
|
219
228
|
private_key = KeyFactory.load_data_private_key(identity[:data], options[:passphrase], ask_passphrase)
|
220
229
|
key = private_key.send(:public_key)
|
@@ -243,9 +252,9 @@ module Net
|
|
243
252
|
def process_identity_loading_error(identity, e)
|
244
253
|
case identity[:load_from]
|
245
254
|
when :pubkey_file
|
246
|
-
error { "could not load public key file `#{identity[:
|
255
|
+
error { "could not load public key file `#{identity[:pubkey_file]}': #{e.class} (#{e.message})" }
|
247
256
|
when :privkey_file
|
248
|
-
error { "could not load private key file `#{identity[:
|
257
|
+
error { "could not load private key file `#{identity[:privkey_file]}': #{e.class} (#{e.message})" }
|
249
258
|
else
|
250
259
|
raise e
|
251
260
|
end
|
@@ -38,8 +38,10 @@ module Net
|
|
38
38
|
debug { "keyboard-interactive info request" }
|
39
39
|
|
40
40
|
unless password
|
41
|
-
|
42
|
-
|
41
|
+
if interactive?
|
42
|
+
puts(name) unless name.empty?
|
43
|
+
puts(instruction) unless instruction.empty?
|
44
|
+
end
|
43
45
|
end
|
44
46
|
|
45
47
|
_ = message.read_string # lang_tag
|
@@ -48,7 +50,8 @@ module Net
|
|
48
50
|
message.read_long.times do
|
49
51
|
text = message.read_string
|
50
52
|
echo = message.read_bool
|
51
|
-
|
53
|
+
password_to_send = password || (interactive? ? prompt(text, echo) : nil)
|
54
|
+
responses << password_to_send
|
52
55
|
end
|
53
56
|
|
54
57
|
# if the password failed the first time around, don't try
|
@@ -62,8 +65,12 @@ module Net
|
|
62
65
|
end
|
63
66
|
end
|
64
67
|
end
|
65
|
-
end
|
66
68
|
|
69
|
+
def interactive?
|
70
|
+
options = session.transport.options || {}
|
71
|
+
!options[:non_interactive]
|
72
|
+
end
|
73
|
+
end
|
67
74
|
end
|
68
75
|
end
|
69
76
|
end
|
@@ -58,7 +58,9 @@ module Net
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def get_max_retries
|
61
|
-
|
61
|
+
options = session.transport.options || {}
|
62
|
+
result = options[:number_of_password_prompts] || NUMBER_OF_PASSWORD_PROMPTS
|
63
|
+
options[:non_interactive] ? 0 : result
|
62
64
|
end
|
63
65
|
end
|
64
66
|
|
@@ -1,10 +1,20 @@
|
|
1
|
-
require 'dl/import'
|
2
|
-
|
3
1
|
if RUBY_VERSION < "1.9"
|
2
|
+
require 'dl/import'
|
4
3
|
require 'dl/struct'
|
5
|
-
|
4
|
+
elsif RUBY_VERSION < "2.2"
|
5
|
+
require 'dl/import'
|
6
6
|
require 'dl/types'
|
7
7
|
require 'dl'
|
8
|
+
else
|
9
|
+
require 'fiddle'
|
10
|
+
require 'fiddle/types'
|
11
|
+
require 'fiddle/import'
|
12
|
+
|
13
|
+
# For now map DL to Fiddler versus updating all the code below
|
14
|
+
module DL
|
15
|
+
CPtr = Fiddle::Pointer
|
16
|
+
RUBY_FREE = Fiddle::RUBY_FREE
|
17
|
+
end
|
8
18
|
end
|
9
19
|
|
10
20
|
require 'net/ssh/errors'
|
@@ -36,12 +46,17 @@ module Net; module SSH; module Authentication
|
|
36
46
|
dlload 'advapi32'
|
37
47
|
|
38
48
|
SIZEOF_DWORD = DL.sizeof('L')
|
39
|
-
|
49
|
+
elsif RUBY_VERSION < "2.2"
|
40
50
|
extend DL::Importer
|
41
51
|
dlload 'user32','kernel32', 'advapi32'
|
42
52
|
include DL::Win32Types
|
43
53
|
|
44
54
|
SIZEOF_DWORD = DL::SIZEOF_LONG
|
55
|
+
else
|
56
|
+
extend Fiddle::Importer
|
57
|
+
dlload 'user32','kernel32', 'advapi32'
|
58
|
+
include Fiddle::Win32Types
|
59
|
+
SIZEOF_DWORD = Fiddle::SIZEOF_LONG
|
45
60
|
end
|
46
61
|
|
47
62
|
typealias("LPCTSTR", "char *") # From winnt.h
|
@@ -138,6 +153,9 @@ module Net; module SSH; module Authentication
|
|
138
153
|
'LPVOID Group', 'LPVOID Sacl',
|
139
154
|
'LPVOID Dacl']
|
140
155
|
|
156
|
+
# The COPYDATASTRUCT is used to send WM_COPYDATA messages
|
157
|
+
COPYDATASTRUCT = struct ['uintptr_t dwData', 'DWORD cbData', 'LPVOID lpData']
|
158
|
+
|
141
159
|
# Compatibility for security attribute retrieval.
|
142
160
|
if RUBY_VERSION < "1.9"
|
143
161
|
# Alias functions to > 1.9 capitalization
|
@@ -198,11 +216,10 @@ module Net; module SSH; module Authentication
|
|
198
216
|
raise_error_if_zero(
|
199
217
|
Win.IsValidSecurityDescriptor(psd_information))
|
200
218
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
sa =
|
205
|
-
bInheritHandle].pack("LLC")
|
219
|
+
sa = Win::SECURITY_ATTRIBUTES.new(malloc_ptr(Win::SECURITY_ATTRIBUTES.size))
|
220
|
+
sa.nLength = Win::SECURITY_ATTRIBUTES.size
|
221
|
+
sa.lpSecurityDescriptor = psd_information.to_i
|
222
|
+
sa.bInheritHandle = 1
|
206
223
|
|
207
224
|
return sa
|
208
225
|
end
|
@@ -350,10 +367,13 @@ module Net; module SSH; module Authentication
|
|
350
367
|
|
351
368
|
Win.set_ptr_data(ptr, query)
|
352
369
|
|
353
|
-
|
354
|
-
|
370
|
+
# using struct to achieve proper alignment and field size on 64-bit platform
|
371
|
+
cds = Win::COPYDATASTRUCT.new(Win.malloc_ptr(Win::COPYDATASTRUCT.size))
|
372
|
+
cds.dwData = AGENT_COPYDATA_ID
|
373
|
+
cds.cbData = mapname.size + 1
|
374
|
+
cds.lpData = Win.get_cstr(mapname)
|
355
375
|
succ = Win.SendMessageTimeout(@win, Win::WM_COPYDATA, Win::NULL,
|
356
|
-
cds, Win::SMTO_NORMAL, 5000, id)
|
376
|
+
cds.to_ptr, Win::SMTO_NORMAL, 5000, id)
|
357
377
|
|
358
378
|
if succ > 0
|
359
379
|
retlen = 4 + ptr.to_s(4).unpack("N")[0]
|
@@ -126,7 +126,7 @@ module Net; module SSH; module Connection
|
|
126
126
|
@pending_requests = []
|
127
127
|
@on_open_failed = @on_data = @on_extended_data = @on_process = @on_close = @on_eof = nil
|
128
128
|
@on_request = {}
|
129
|
-
@closing = @eof = @sent_eof =
|
129
|
+
@closing = @eof = @sent_eof = false
|
130
130
|
end
|
131
131
|
|
132
132
|
# A shortcut for accessing properties of the channel (see #properties).
|
@@ -269,28 +269,14 @@ module Net; module SSH; module Connection
|
|
269
269
|
connection.loop { active? }
|
270
270
|
end
|
271
271
|
|
272
|
-
#
|
273
|
-
#
|
274
|
-
#
|
275
|
-
#
|
276
|
-
# sending buffered output to server.
|
272
|
+
# Returns true if the channel is currently closing, but not actually
|
273
|
+
# closed. A channel is closing when, for instance, #close has been
|
274
|
+
# invoked, but the server has not yet responded with a CHANNEL_CLOSE
|
275
|
+
# packet of its own.
|
277
276
|
def closing?
|
278
277
|
@closing
|
279
278
|
end
|
280
279
|
|
281
|
-
# True if we have sent CHANNEL_CLOSE to the remote server.
|
282
|
-
def local_closed?
|
283
|
-
@local_closed
|
284
|
-
end
|
285
|
-
|
286
|
-
def remote_closed?
|
287
|
-
@remote_closed
|
288
|
-
end
|
289
|
-
|
290
|
-
def remote_closed!
|
291
|
-
@remote_closed = true
|
292
|
-
end
|
293
|
-
|
294
280
|
# Requests that the channel be closed. If the channel is already closing,
|
295
281
|
# this does nothing, nor does it do anything if the channel has not yet
|
296
282
|
# been confirmed open (see #do_open_confirmation). Otherwise, it sends a
|
@@ -299,6 +285,7 @@ module Net; module SSH; module Connection
|
|
299
285
|
return if @closing
|
300
286
|
if remote_id
|
301
287
|
@closing = true
|
288
|
+
connection.send_message(Buffer.from(:byte, CHANNEL_CLOSE, :long, remote_id))
|
302
289
|
end
|
303
290
|
end
|
304
291
|
|
@@ -324,16 +311,10 @@ module Net; module SSH; module Connection
|
|
324
311
|
@on_process.call(self) if @on_process
|
325
312
|
enqueue_pending_output
|
326
313
|
|
327
|
-
if @eof and not @sent_eof and output.empty? and remote_id
|
314
|
+
if @eof and not @sent_eof and output.empty? and remote_id
|
328
315
|
connection.send_message(Buffer.from(:byte, CHANNEL_EOF, :long, remote_id))
|
329
316
|
@sent_eof = true
|
330
317
|
end
|
331
|
-
|
332
|
-
if @closing and not @local_closed and output.empty? and remote_id
|
333
|
-
connection.send_message(Buffer.from(:byte, CHANNEL_CLOSE, :long, remote_id))
|
334
|
-
@local_closed = true
|
335
|
-
connection.cleanup_channel(self)
|
336
|
-
end
|
337
318
|
end
|
338
319
|
|
339
320
|
# Registers a callback to be invoked when data packets are received by the
|
@@ -220,7 +220,7 @@ module Net; module SSH; module Connection
|
|
220
220
|
def preprocess
|
221
221
|
return false if block_given? && !yield(self)
|
222
222
|
dispatch_incoming_packets
|
223
|
-
channels.each { |id, channel| channel.process unless channel.
|
223
|
+
channels.each { |id, channel| channel.process unless channel.closing? }
|
224
224
|
return false if block_given? && !yield(self)
|
225
225
|
return true
|
226
226
|
end
|
@@ -453,14 +453,6 @@ module Net; module SSH; module Connection
|
|
453
453
|
old
|
454
454
|
end
|
455
455
|
|
456
|
-
def cleanup_channel(channel)
|
457
|
-
if channel.local_closed? and channel.remote_closed?
|
458
|
-
info { "#{host} delete channel #{channel.local_id} which closed locally and remotely" }
|
459
|
-
channels.delete(channel.local_id)
|
460
|
-
end
|
461
|
-
end
|
462
|
-
|
463
|
-
|
464
456
|
private
|
465
457
|
|
466
458
|
# Read all pending packets from the connection and dispatch them as
|
@@ -589,10 +581,9 @@ module Net; module SSH; module Connection
|
|
589
581
|
info { "channel_close: #{packet[:local_id]}" }
|
590
582
|
|
591
583
|
channel = channels[packet[:local_id]]
|
592
|
-
channel.remote_closed!
|
593
584
|
channel.close
|
594
585
|
|
595
|
-
|
586
|
+
channels.delete(packet[:local_id])
|
596
587
|
channel.do_close
|
597
588
|
end
|
598
589
|
|