net-ssh 2.9.4 → 2.10.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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.travis.yml +11 -4
  5. data/CHANGES.txt +15 -5
  6. data/README.rdoc +1 -1
  7. data/Rakefile +12 -5
  8. data/lib/net/ssh.rb +16 -1
  9. data/lib/net/ssh/authentication/key_manager.rb +20 -11
  10. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +11 -4
  11. data/lib/net/ssh/authentication/methods/password.rb +3 -1
  12. data/lib/net/ssh/authentication/pageant.rb +32 -12
  13. data/lib/net/ssh/connection/channel.rb +7 -26
  14. data/lib/net/ssh/connection/session.rb +2 -11
  15. data/lib/net/ssh/proxy/command.rb +14 -3
  16. data/lib/net/ssh/ruby_compat.rb +0 -5
  17. data/lib/net/ssh/transport/algorithms.rb +3 -4
  18. data/lib/net/ssh/transport/cipher_factory.rb +0 -1
  19. data/lib/net/ssh/transport/session.rb +8 -7
  20. data/lib/net/ssh/version.rb +4 -4
  21. data/net-ssh-public_cert.pem +15 -15
  22. data/net-ssh.gemspec +9 -5
  23. data/setup.rb +1 -1
  24. data/test/README.txt +6 -13
  25. data/test/authentication/methods/test_keyboard_interactive.rb +21 -0
  26. data/test/authentication/test_key_manager.rb +5 -1
  27. data/test/connection/test_channel.rb +0 -3
  28. data/test/connection/test_session.rb +8 -17
  29. data/test/integration/README.txt +19 -0
  30. data/test/integration/Vagrantfile +12 -0
  31. data/test/integration/common.rb +57 -0
  32. data/test/integration/playbook.yml +46 -0
  33. data/test/integration/test_id_rsa_keys.rb +78 -0
  34. data/test/start/test_options.rb +8 -1
  35. data/test/test_all.rb +1 -0
  36. data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +5 -1
  37. data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +5 -1
  38. data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +2 -17
  39. data/test/transport/test_algorithms.rb +21 -17
  40. data/test/transport/test_session.rb +1 -1
  41. metadata +24 -20
  42. metadata.gz.sig +0 -0
  43. data/Rudyfile +0 -96
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e7f14fbfcfd32cc75f187e18b727926b727993ec
4
- data.tar.gz: 5aba78f7570373c5cbb0b441b620ade113c356d5
3
+ metadata.gz: 99ac97b623723117ba47a0785cf3dc7d2e1ae594
4
+ data.tar.gz: 705651920fb196430521248ef4d457a955814ac6
5
5
  SHA512:
6
- metadata.gz: 0f9f618270c98f579a6cb999fab3b4d1d58c38e200db68931c911cd8055a3e8cc51d1a84246de80889a5dabb1c138af5607d955766143d9a512ea5f2f6b95fc5
7
- data.tar.gz: 5628810355c03a737accd6fae7225287183397edcce63b14a090caec1f3722455f6c98b76d4b4d5b11f19515ebe0f6ef3a78b37b4ef4fcd2ce4c8a868c786574
6
+ metadata.gz: e6a3403271ad3a629769a30b99a9e4802f918444d0c3b97ef8f2df955ae9b2aeac2eaf0c64454227c4d74ac375d3ccf0e60ee7e19518cf1e63f424dd22d3dceb
7
+ data.tar.gz: f84cae92e328113fa58bfd19e0e828412fe1bdce7bc0fa2cdca254b7c25562c0efcd1a9de5987de3be6180f5c64583baee4f560b748f65d37eabd0760529eadf
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -1,10 +1,17 @@
1
1
  language: ruby
2
2
  rvm:
3
- - "1.9.3"
4
- - "2.0.0"
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
@@ -1,10 +1,20 @@
1
- === 2.9.4-rc1
1
+ === 2.10.0-?
2
2
 
3
- * Bugfix: CHANNEL_CLOSE was sent before draining ouput buffer #280 [Christopher F. Auston]
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
- [Note: 2.9.3 release changes went to 3.0, 2.9.4 is backport of fix form 3.0]
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
@@ -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. Later releases will work but the test suite is no longer guaranteed to pass all tests.
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
@@ -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
- public_key_file = file + ".pub"
191
- if File.readable?(public_key_file)
192
- { :load_from => :pubkey_file, :file => file }
193
- elsif File.readable?(file)
194
- { :load_from => :privkey_file, :file => file }
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[:file] + ".pub")
213
- { :public_key => key, :from => :file, :file => identity[:file] }
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[:file], options[:passphrase], ask_passphrase)
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[:file], :key => private_key }
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[:file]}': #{e.class} (#{e.message})" }
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[:file]}': #{e.class} (#{e.message})" }
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
- puts(name) unless name.empty?
42
- puts(instruction) unless instruction.empty?
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
- responses << (password || prompt(text, echo))
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
- (session.transport.options||{})[:number_of_password_prompts] || NUMBER_OF_PASSWORD_PROMPTS
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
- else
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
- else
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
- nLength = Win::SECURITY_ATTRIBUTES.size
202
- lpSecurityDescriptor = psd_information
203
- bInheritHandle = 1
204
- sa = [nLength, lpSecurityDescriptor.to_i,
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
- cds = Win.get_ptr [AGENT_COPYDATA_ID, mapname.size + 1,
354
- Win.get_cstr(mapname)].pack("LLp")
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 = @local_closed = @remote_closed = false
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
- # True if close() has been called; NOTE: if the channel has data waiting to
273
- # be sent then the channel will close after all the data is sent. See
274
- # closed?() to determine if we have actually sent CHANNEL_CLOSE to server.
275
- # This may be true for awhile before closed? returns true if we are still
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 and not @local_closed
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.local_closed? }
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
- cleanup_channel(channel)
586
+ channels.delete(packet[:local_id])
596
587
  channel.do_close
597
588
  end
598
589