net-ssh 2.9.4 → 3.0.1
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/.travis.yml +12 -4
- data/CHANGES.txt +43 -5
- data/README.rdoc +8 -50
- data/Rakefile +13 -5
- data/lib/net/ssh/authentication/key_manager.rb +28 -19
- 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 +42 -22
- data/lib/net/ssh/connection/channel.rb +7 -26
- data/lib/net/ssh/connection/session.rb +7 -14
- data/lib/net/ssh/known_hosts.rb +20 -1
- data/lib/net/ssh/proxy/command.rb +14 -3
- data/lib/net/ssh/proxy/http.rb +3 -2
- data/lib/net/ssh/proxy/socks4.rb +2 -1
- data/lib/net/ssh/proxy/socks5.rb +3 -2
- 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/server_version.rb +9 -3
- data/lib/net/ssh/transport/session.rb +11 -9
- data/lib/net/ssh/version.rb +4 -4
- data/lib/net/ssh.rb +17 -2
- data/net-ssh-public_cert.pem +15 -15
- data/net-ssh.gemspec +11 -4
- 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 +14 -1
- data/test/configs/proxy_remote_user +2 -0
- data/test/connection/test_channel.rb +0 -3
- data/test/connection/test_session.rb +15 -21
- 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 +48 -0
- data/test/integration/test_id_rsa_keys.rb +84 -0
- data/test/known_hosts/github_hash +1 -0
- data/test/start/test_options.rb +15 -1
- data/test/test_all.rb +1 -0
- data/test/test_config.rb +6 -0
- data/test/test_known_hosts.rb +11 -3
- 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_packet_stream.rb +1 -0
- data/test/transport/test_session.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +25 -19
- 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: 95e458a7ed58017d4658db4ac2b3126a0f09d43f
|
|
4
|
+
data.tar.gz: 1840e7ee533d79e4a42bb2e42cd1c3d6e31da5f8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1906d2443742af07de4b8dad4b7c3f85cde768f703f4e445f0cbd249311febd8e9e33d276b37d90af4119d702b6dc5d4a7b7cc3e9b581b63444dd87d7141732c
|
|
7
|
+
data.tar.gz: edefc22e10946ea02716b0665c83f1d99ebc2db02f26c36f42dcc2e310dbb33052f749eb20f2726cbd361be007954d831f6740c37da8c43280472112ccdb2e3e
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/.travis.yml
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
language: ruby
|
|
2
|
+
sudo: false
|
|
2
3
|
rvm:
|
|
3
|
-
-
|
|
4
|
-
-
|
|
4
|
+
- 1.9.3
|
|
5
|
+
- 2.0.0
|
|
6
|
+
- 2.1.0
|
|
7
|
+
- 2.2.0
|
|
8
|
+
- jruby-head
|
|
9
|
+
- jruby-19mode
|
|
10
|
+
- rbx-2
|
|
5
11
|
|
|
6
|
-
|
|
7
|
-
install: gem install jeweler test-unit mocha
|
|
12
|
+
install: gem install test-unit mocha
|
|
8
13
|
|
|
9
14
|
script: rake test
|
|
10
15
|
|
|
16
|
+
matrix:
|
|
17
|
+
allow_failures:
|
|
18
|
+
- rvm: jruby-head
|
data/CHANGES.txt
CHANGED
|
@@ -1,10 +1,48 @@
|
|
|
1
|
-
===
|
|
1
|
+
=== 3.0.1
|
|
2
|
+
=== 3.0.1.rc1
|
|
2
3
|
|
|
3
|
-
*
|
|
4
|
+
* Breaking change from 2.* series: exec! without block now returns empty string instread of nil if command has no output [https://github.com/net-ssh/net-ssh/pull/273]
|
|
5
|
+
* Support remote_user as %r in proxy commands [Dominic Scheirlinck]
|
|
6
|
+
* Raise Net::SSH::ConnectionTimeout from connection timeout [Carl Hoerberg]
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
=== 3.0.0.rc1
|
|
9
|
+
|
|
10
|
+
* SemVer: Major version change because of dropping of ruby 1.9
|
|
11
|
+
|
|
12
|
+
=== 2.10.1.rc2
|
|
13
|
+
|
|
14
|
+
* Win: Use fiddle on ruby 2.1 too [Charlie Savage]
|
|
15
|
+
|
|
16
|
+
=== 2.10.1.rc1
|
|
17
|
+
|
|
18
|
+
* Added ruby 2.0 requirement to gemspec [Alex Schultz]
|
|
19
|
+
|
|
20
|
+
=== 2.10.0
|
|
21
|
+
|
|
22
|
+
=== 2.10.0-beta2
|
|
23
|
+
|
|
24
|
+
* Fix :passphrase option with :non_interactive [Jeremy Stanley]
|
|
25
|
+
* Use Socket.tcp with connect_timeout instead of Timeout::timeout [Carl Hörberg]
|
|
26
|
+
* Support for hostname hashes [Jef Mathiot]
|
|
27
|
+
* Ruby 1.9.3 is no longer supported but should moslty work expect for stuff like connect_timeout
|
|
28
|
+
|
|
29
|
+
=== 2.10.0-beta1
|
|
30
|
+
|
|
31
|
+
* Fix could not parse PKey error. [Andrey Voronkov]
|
|
32
|
+
* Workaround for threading issue in MRI + singleton method declaration [Matt Brictson]
|
|
33
|
+
* 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]
|
|
34
|
+
* New configuration option: :non_interactive => true in case you prefer an authmethod to fail rather than prompt. [mfazekas]
|
|
35
|
+
* Configuration change: password will now ask for password up to the :number_of_password_prompts times. If you want the
|
|
36
|
+
2.9.1 behaviour of never asking password please set number_of_password_prompts to 0.
|
|
37
|
+
|
|
38
|
+
=== 2.9.4-beta1
|
|
39
|
+
|
|
40
|
+
* Use sysread and syswrite on Windows instead of read_nonblock and write [marc-etienne]
|
|
41
|
+
* Windows/peagant: use fiddle on ruby 2.2+/windows [Charlie Savage]
|
|
42
|
+
* Check if ssh key is a file [kiela]
|
|
43
|
+
|
|
44
|
+
=== 2.9.3
|
|
6
45
|
|
|
7
|
-
=== 2.9.2
|
|
8
46
|
=== 2.9.2-rc3
|
|
9
47
|
|
|
10
48
|
* Remove advertised algorithms that were not working (curve25519-sha256@libssh.org) [mfazekas]
|
|
@@ -21,7 +59,7 @@
|
|
|
21
59
|
|
|
22
60
|
* Remove advertised algorithms that were not working (ssh-rsa-cert-* *ed25519 acm*-gcm@openssh.com) [mfazekas]
|
|
23
61
|
* Unkown algorithms now ignored instead of failed [mfazekas]
|
|
24
|
-
* Asks for password with password auth (up to number_of_password_prompts) [mfazekas]
|
|
62
|
+
* Configuration change: Asks for password with password auth (up to number_of_password_prompts) [mfazekas]
|
|
25
63
|
* Removed warnings [amatsuda]
|
|
26
64
|
|
|
27
65
|
=== 2.9.1 / 13 May 2014
|
data/README.rdoc
CHANGED
|
@@ -32,6 +32,7 @@ In a nutshell:
|
|
|
32
32
|
Net::SSH.start('host', 'user', :password => "password") do |ssh|
|
|
33
33
|
# capture all stderr and stdout output from a remote process
|
|
34
34
|
output = ssh.exec!("hostname")
|
|
35
|
+
puts output
|
|
35
36
|
|
|
36
37
|
# capture only stdout matching a particular pattern
|
|
37
38
|
stdout = ""
|
|
@@ -101,8 +102,8 @@ However, in order to be sure the code you're installing hasn't been tampered wit
|
|
|
101
102
|
|
|
102
103
|
# Add the public key as a trusted certificate
|
|
103
104
|
# (You only need to do this once)
|
|
104
|
-
$ curl -O https://raw.
|
|
105
|
-
$ gem cert --add
|
|
105
|
+
$ curl -O https://raw.githubusercontent.com/net-ssh/net-ssh/master/net-ssh-public_cert.pem
|
|
106
|
+
$ gem cert --add net-ssh-public_cert.pem
|
|
106
107
|
|
|
107
108
|
Then, when install the gem, do so with high security:
|
|
108
109
|
|
|
@@ -110,47 +111,11 @@ Then, when install the gem, do so with high security:
|
|
|
110
111
|
|
|
111
112
|
If you don't add the public key, you'll see an error like "Couldn't verify data signature". If you're still having trouble let me know and I'll give you a hand.
|
|
112
113
|
|
|
113
|
-
== RUBY 1.
|
|
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.
|
|
116
|
-
|
|
117
|
-
== JRUBY 1.6
|
|
118
|
-
|
|
119
|
-
There is an issue with jruby-openssl that produces the following error in jruby 1.6:
|
|
120
|
-
|
|
121
|
-
<ArgumentError> wrong number of arguments (2 for 1)
|
|
122
|
-
/home/offers/tracking/shared/bundle/jruby/1.8/gems/net-ssh-2.6.0/lib/net/ssh/key_factory.rb:77:in `load_data_private_key'
|
|
123
|
-
|
|
124
|
-
You can downgrade jruby-openssl to version 0.7.4 (before they added the PKey.read method) to resolve it or upgrade jruby to 1.7. See issue #61 for more info: https://github.com/net-ssh/net-ssh/issues/61.
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
== ARCFOUR SUPPORT:
|
|
128
|
-
|
|
129
|
-
from Karl Varga:
|
|
130
|
-
|
|
131
|
-
Ruby's OpenSSL bindings always return a key length of 16 for RC4 ciphers, which means that when we try to use ARCFOUR256 or higher, Net::SSH generates keys which are consistently too short - 16 bytes as opposed to 32 bytes - resulting in the following error:
|
|
132
|
-
|
|
133
|
-
OpenSSL::CipherError: key length too short
|
|
134
|
-
|
|
135
|
-
My patch simply instructs Net::SSH to build keys of the the proper length, regardless of the required key length reported by OpenSSL.
|
|
136
|
-
|
|
137
|
-
You should also be aware that your OpenSSL C libraries may also contain this bug. I've updated to 0.9.8k, but according to this thread[https://bugzilla.mindrot.org/show_bug.cgi?id=1291], the bug existed as recently as 0.9.8e! I've manually taken a look at my header files and they look ok, which is what makes me think it's a bug in the Ruby implementation.
|
|
138
|
-
|
|
139
|
-
To see your OpenSSL version:
|
|
140
|
-
|
|
141
|
-
$ openssl version
|
|
142
|
-
OpenSSL 0.9.8k 25 Mar 2009
|
|
143
|
-
|
|
144
|
-
After installing this gem, verify that Net::SSH is generating keys of the correct length by running the script <tt>support/arcfour_check.rb</tt>:
|
|
145
|
-
|
|
146
|
-
$ ruby arcfour_support.rb
|
|
147
|
-
|
|
148
|
-
which should produce the following:
|
|
149
|
-
|
|
150
|
-
arcfour128: [16, 8] OpenSSL::Cipher::Cipher
|
|
151
|
-
arcfour256: [32, 8] OpenSSL::Cipher::Cipher
|
|
152
|
-
arcfour512: [64, 8] OpenSSL::Cipher::Cipher
|
|
114
|
+
== RUBY 1.x SUPPORT
|
|
153
115
|
|
|
116
|
+
* Ruby 1.8.x is supported up until the net-ssh 2.5.1 release.
|
|
117
|
+
* Ruby 1.9.x is supported up until the net-ssh 2.9.x release.
|
|
118
|
+
* Current net-ssh releases require Ruby 2.0 or later.
|
|
154
119
|
|
|
155
120
|
== RUNNING TESTS
|
|
156
121
|
|
|
@@ -162,14 +127,7 @@ Run a single test file like this:
|
|
|
162
127
|
|
|
163
128
|
ruby -Ilib -Itest -rrubygems test/transport/test_server_version.rb
|
|
164
129
|
|
|
165
|
-
|
|
166
|
-
=== EXPECTED RESULTS
|
|
167
|
-
|
|
168
|
-
* Ruby 1.8: all tests pass
|
|
169
|
-
|
|
170
|
-
* Ruby 1.9: all tests pass
|
|
171
|
-
|
|
172
|
-
* JRuby 1.5: 99% tests pass (448 tests, 1846 assertions, 1 failures)
|
|
130
|
+
To run integration tests see test/integration/README.txt
|
|
173
131
|
|
|
174
132
|
=== BUILDING GEM
|
|
175
133
|
|
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"]
|
|
@@ -29,6 +30,7 @@ begin
|
|
|
29
30
|
s.email = "net-ssh@solutious.com"
|
|
30
31
|
s.homepage = "https://github.com/net-ssh/net-ssh"
|
|
31
32
|
s.authors = ["Jamis Buck", "Delano Mandelbaum", "Miklós Fazekas"]
|
|
33
|
+
s.required_ruby_version = '>= 2.0'
|
|
32
34
|
|
|
33
35
|
# Note: this is run at package time not install time so if you are
|
|
34
36
|
# running on jruby, you need to install jruby-pageant manually.
|
|
@@ -55,11 +57,6 @@ rescue LoadError
|
|
|
55
57
|
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
|
56
58
|
end
|
|
57
59
|
|
|
58
|
-
require 'rake/testtask'
|
|
59
|
-
Rake::TestTask.new do |t|
|
|
60
|
-
t.libs = ["lib", "test"]
|
|
61
|
-
end
|
|
62
|
-
|
|
63
60
|
extra_files = %w[LICENSE.txt THANKS.txt CHANGES.txt ]
|
|
64
61
|
RDoc::Task.new do |rdoc|
|
|
65
62
|
rdoc.rdoc_dir = "rdoc"
|
|
@@ -73,3 +70,14 @@ RDoc::Task.new do |rdoc|
|
|
|
73
70
|
rdoc.rdoc_files.include(file) if File.exists?(file)
|
|
74
71
|
}
|
|
75
72
|
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
require 'rake/testtask'
|
|
76
|
+
Rake::TestTask.new do |t|
|
|
77
|
+
t.libs = ["lib", "test"]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
Rake::TestTask.new(:'integration-test') do |t|
|
|
81
|
+
t.libs = ["lib", "test/integration"]
|
|
82
|
+
t.pattern = 'test/integration/test_*.rb'
|
|
83
|
+
end
|
|
@@ -98,7 +98,7 @@ module Net
|
|
|
98
98
|
def each_identity
|
|
99
99
|
prepared_identities = prepare_identities_from_files + prepare_identities_from_data
|
|
100
100
|
|
|
101
|
-
user_identities = load_identities(prepared_identities, false)
|
|
101
|
+
user_identities = load_identities(prepared_identities, false, true)
|
|
102
102
|
|
|
103
103
|
if agent
|
|
104
104
|
agent.identities.each do |key|
|
|
@@ -114,7 +114,7 @@ module Net
|
|
|
114
114
|
end
|
|
115
115
|
end
|
|
116
116
|
|
|
117
|
-
user_identities = load_identities(user_identities,
|
|
117
|
+
user_identities = load_identities(user_identities, !options[:non_interactive], false)
|
|
118
118
|
|
|
119
119
|
user_identities.each do |identity|
|
|
120
120
|
key = identity.delete(:public_key)
|
|
@@ -139,7 +139,7 @@ module Net
|
|
|
139
139
|
|
|
140
140
|
if info[:key].nil? && info[:from] == :file
|
|
141
141
|
begin
|
|
142
|
-
info[:key] = KeyFactory.load_private_key(info[:file], options[:passphrase],
|
|
142
|
+
info[:key] = KeyFactory.load_private_key(info[:file], options[:passphrase], !options[:non_interactive])
|
|
143
143
|
rescue Exception, OpenSSL::OpenSSLError => e
|
|
144
144
|
raise KeyManagerError, "the given identity is known, but the private key could not be loaded: #{e.class} (#{e.message})"
|
|
145
145
|
end
|
|
@@ -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|
|
|
@@ -203,18 +212,18 @@ module Net
|
|
|
203
212
|
end
|
|
204
213
|
end
|
|
205
214
|
|
|
206
|
-
# Load prepared identities. Private key decryption errors ignored if
|
|
207
|
-
def load_identities(identities, ask_passphrase)
|
|
215
|
+
# Load prepared identities. Private key decryption errors ignored if ignore_decryption_errors
|
|
216
|
+
def load_identities(identities, ask_passphrase, ignore_decryption_errors)
|
|
208
217
|
identities.map do |identity|
|
|
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)
|
|
@@ -224,11 +233,11 @@ module Net
|
|
|
224
233
|
end
|
|
225
234
|
|
|
226
235
|
rescue OpenSSL::PKey::RSAError, OpenSSL::PKey::DSAError, OpenSSL::PKey::ECError => e
|
|
227
|
-
if
|
|
236
|
+
if ignore_decryption_errors
|
|
237
|
+
identity
|
|
238
|
+
else
|
|
228
239
|
process_identity_loading_error(identity, e)
|
|
229
240
|
nil
|
|
230
|
-
else
|
|
231
|
-
identity
|
|
232
241
|
end
|
|
233
242
|
rescue ArgumentError => e
|
|
234
243
|
process_identity_loading_error(identity, e)
|
|
@@ -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.1"
|
|
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.1"
|
|
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
|
|
@@ -73,7 +88,7 @@ module Net; module SSH; module Authentication
|
|
|
73
88
|
extern 'HANDLE CreateFileMapping(HANDLE, void *, DWORD, ' +
|
|
74
89
|
'DWORD, DWORD, LPCTSTR)'
|
|
75
90
|
|
|
76
|
-
# args: hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh,
|
|
91
|
+
# args: hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh,
|
|
77
92
|
# dwfileOffsetLow, dwNumberOfBytesToMap
|
|
78
93
|
extern 'LPVOID MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, DWORD)'
|
|
79
94
|
|
|
@@ -86,7 +101,7 @@ module Net; module SSH; module Authentication
|
|
|
86
101
|
# args: hWnd, Msg, wParam, lParam, fuFlags, uTimeout, lpdwResult
|
|
87
102
|
extern 'LRESULT SendMessageTimeout(HWND, UINT, WPARAM, LPARAM, ' +
|
|
88
103
|
'UINT, UINT, PDWORD_PTR)'
|
|
89
|
-
|
|
104
|
+
|
|
90
105
|
# args: none
|
|
91
106
|
extern 'DWORD GetLastError()'
|
|
92
107
|
|
|
@@ -112,8 +127,8 @@ module Net; module SSH; module Authentication
|
|
|
112
127
|
extern 'BOOL IsValidSecurityDescriptor(LPVOID)'
|
|
113
128
|
|
|
114
129
|
# Constants needed for security attribute retrieval.
|
|
115
|
-
# Specifies the access mask corresponding to the desired access
|
|
116
|
-
# rights.
|
|
130
|
+
# Specifies the access mask corresponding to the desired access
|
|
131
|
+
# rights.
|
|
117
132
|
TOKEN_QUERY = 0x8
|
|
118
133
|
|
|
119
134
|
# The value of TOKEN_USER from the TOKEN_INFORMATION_CLASS enum.
|
|
@@ -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
|
|
@@ -278,7 +295,7 @@ module Net; module SSH; module Authentication
|
|
|
278
295
|
new
|
|
279
296
|
end
|
|
280
297
|
|
|
281
|
-
# Create a new instance that communicates with the running pageant
|
|
298
|
+
# Create a new instance that communicates with the running pageant
|
|
282
299
|
# instance. If no such instance is running, this will cause an error.
|
|
283
300
|
def initialize
|
|
284
301
|
@win = Win.FindWindow("Pageant", "Pageant")
|
|
@@ -296,20 +313,20 @@ module Net; module SSH; module Authentication
|
|
|
296
313
|
# the first.
|
|
297
314
|
def send(data, *args)
|
|
298
315
|
@input_buffer.append(data)
|
|
299
|
-
|
|
316
|
+
|
|
300
317
|
ret = data.length
|
|
301
|
-
|
|
318
|
+
|
|
302
319
|
while true
|
|
303
320
|
return ret if @input_buffer.length < 4
|
|
304
321
|
msg_length = @input_buffer.read_long + 4
|
|
305
322
|
@input_buffer.reset!
|
|
306
|
-
|
|
323
|
+
|
|
307
324
|
return ret if @input_buffer.length < msg_length
|
|
308
325
|
msg = @input_buffer.read!(msg_length)
|
|
309
326
|
@output_buffer.append(send_query(msg))
|
|
310
327
|
end
|
|
311
328
|
end
|
|
312
|
-
|
|
329
|
+
|
|
313
330
|
# Reads +n+ bytes from the cached result of the last query. If +n+
|
|
314
331
|
# is +nil+, returns all remaining data from the last query.
|
|
315
332
|
def read(n = nil)
|
|
@@ -341,7 +358,7 @@ module Net; module SSH; module Authentication
|
|
|
341
358
|
"Creation of file mapping failed with error: #{Win.GetLastError}"
|
|
342
359
|
end
|
|
343
360
|
|
|
344
|
-
ptr = Win.MapViewOfFile(filemap, Win::FILE_MAP_WRITE, 0, 0,
|
|
361
|
+
ptr = Win.MapViewOfFile(filemap, Win::FILE_MAP_WRITE, 0, 0,
|
|
345
362
|
0)
|
|
346
363
|
|
|
347
364
|
if ptr.nil? || ptr.null?
|
|
@@ -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
|
|
@@ -351,19 +351,21 @@ module Net; module SSH; module Connection
|
|
|
351
351
|
end
|
|
352
352
|
|
|
353
353
|
# Same as #exec, except this will block until the command finishes. Also,
|
|
354
|
-
# if
|
|
354
|
+
# if no block is given, this will return all output (stdout and stderr)
|
|
355
355
|
# as a single string.
|
|
356
356
|
#
|
|
357
357
|
# matches = ssh.exec!("grep something /some/files")
|
|
358
358
|
def exec!(command, &block)
|
|
359
|
-
block
|
|
359
|
+
block_or_concat = block || Proc.new do |ch, type, data|
|
|
360
360
|
ch[:result] ||= ""
|
|
361
361
|
ch[:result] << data
|
|
362
362
|
end
|
|
363
363
|
|
|
364
|
-
channel = exec(command, &
|
|
364
|
+
channel = exec(command, &block_or_concat)
|
|
365
365
|
channel.wait
|
|
366
366
|
|
|
367
|
+
channel[:result] ||= "" unless block
|
|
368
|
+
|
|
367
369
|
return channel[:result]
|
|
368
370
|
end
|
|
369
371
|
|
|
@@ -453,14 +455,6 @@ module Net; module SSH; module Connection
|
|
|
453
455
|
old
|
|
454
456
|
end
|
|
455
457
|
|
|
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
458
|
private
|
|
465
459
|
|
|
466
460
|
# Read all pending packets from the connection and dispatch them as
|
|
@@ -589,10 +583,9 @@ module Net; module SSH; module Connection
|
|
|
589
583
|
info { "channel_close: #{packet[:local_id]}" }
|
|
590
584
|
|
|
591
585
|
channel = channels[packet[:local_id]]
|
|
592
|
-
channel.remote_closed!
|
|
593
586
|
channel.close
|
|
594
587
|
|
|
595
|
-
|
|
588
|
+
channels.delete(packet[:local_id])
|
|
596
589
|
channel.do_close
|
|
597
590
|
end
|
|
598
591
|
|