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.
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