net-ssh 5.0.2 → 7.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/.dockerignore +6 -0
- data/.github/config/rubocop_linter_action.yml +4 -0
- data/.github/workflows/ci-with-docker.yml +44 -0
- data/.github/workflows/ci.yml +87 -0
- data/.github/workflows/rubocop.yml +13 -0
- data/.gitignore +3 -0
- data/.rubocop.yml +19 -2
- data/.rubocop_todo.yml +623 -511
- data/CHANGES.txt +76 -0
- data/Dockerfile +27 -0
- data/Dockerfile.openssl3 +17 -0
- data/Gemfile +2 -0
- data/Gemfile.noed25519 +2 -0
- data/Manifest +0 -1
- data/README.md +293 -0
- data/Rakefile +6 -2
- data/appveyor.yml +4 -2
- data/docker-compose.yml +23 -0
- data/lib/net/ssh/authentication/agent.rb +36 -14
- data/lib/net/ssh/authentication/certificate.rb +19 -7
- data/lib/net/ssh/authentication/constants.rb +0 -1
- data/lib/net/ssh/authentication/ed25519.rb +83 -50
- data/lib/net/ssh/authentication/ed25519_loader.rb +5 -8
- data/lib/net/ssh/authentication/key_manager.rb +74 -33
- data/lib/net/ssh/authentication/methods/abstract.rb +12 -3
- data/lib/net/ssh/authentication/methods/hostbased.rb +3 -5
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +5 -3
- data/lib/net/ssh/authentication/methods/none.rb +6 -9
- data/lib/net/ssh/authentication/methods/password.rb +2 -3
- data/lib/net/ssh/authentication/methods/publickey.rb +58 -16
- data/lib/net/ssh/authentication/pageant.rb +97 -97
- data/lib/net/ssh/authentication/pub_key_fingerprint.rb +2 -3
- data/lib/net/ssh/authentication/session.rb +27 -23
- data/lib/net/ssh/buffer.rb +91 -40
- data/lib/net/ssh/buffered_io.rb +24 -26
- data/lib/net/ssh/config.rb +99 -53
- data/lib/net/ssh/connection/channel.rb +101 -87
- data/lib/net/ssh/connection/constants.rb +0 -4
- data/lib/net/ssh/connection/event_loop.rb +30 -25
- data/lib/net/ssh/connection/keepalive.rb +12 -12
- data/lib/net/ssh/connection/session.rb +115 -111
- data/lib/net/ssh/connection/term.rb +56 -58
- data/lib/net/ssh/errors.rb +12 -12
- data/lib/net/ssh/key_factory.rb +108 -22
- data/lib/net/ssh/known_hosts.rb +120 -36
- data/lib/net/ssh/loggable.rb +10 -11
- data/lib/net/ssh/packet.rb +1 -1
- data/lib/net/ssh/prompt.rb +9 -11
- data/lib/net/ssh/proxy/command.rb +1 -2
- data/lib/net/ssh/proxy/errors.rb +2 -4
- data/lib/net/ssh/proxy/http.rb +18 -20
- data/lib/net/ssh/proxy/https.rb +8 -10
- data/lib/net/ssh/proxy/jump.rb +8 -10
- data/lib/net/ssh/proxy/socks4.rb +2 -4
- data/lib/net/ssh/proxy/socks5.rb +3 -6
- data/lib/net/ssh/service/forward.rb +9 -8
- data/lib/net/ssh/test/channel.rb +24 -26
- data/lib/net/ssh/test/extensions.rb +37 -35
- 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 +3 -3
- data/lib/net/ssh/test/remote_packet.rb +6 -8
- data/lib/net/ssh/test/script.rb +25 -27
- data/lib/net/ssh/test/socket.rb +12 -15
- data/lib/net/ssh/test.rb +12 -12
- data/lib/net/ssh/transport/algorithms.rb +177 -118
- data/lib/net/ssh/transport/cipher_factory.rb +34 -50
- data/lib/net/ssh/transport/constants.rb +13 -9
- data/lib/net/ssh/transport/ctr.rb +8 -14
- data/lib/net/ssh/transport/hmac/abstract.rb +20 -5
- 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/hmac/sha2_256.rb +7 -11
- data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
- data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
- data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
- data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac.rb +13 -11
- data/lib/net/ssh/transport/identity_cipher.rb +11 -13
- data/lib/net/ssh/transport/kex/abstract.rb +130 -0
- data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +5 -19
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +30 -139
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +1 -8
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +20 -81
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +5 -4
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +5 -4
- data/lib/net/ssh/transport/kex.rb +15 -10
- data/lib/net/ssh/transport/key_expander.rb +7 -8
- data/lib/net/ssh/transport/openssl.rb +149 -111
- data/lib/net/ssh/transport/packet_stream.rb +53 -22
- data/lib/net/ssh/transport/server_version.rb +17 -16
- data/lib/net/ssh/transport/session.rb +35 -11
- data/lib/net/ssh/transport/state.rb +44 -44
- data/lib/net/ssh/verifiers/accept_new.rb +7 -2
- data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +1 -2
- data/lib/net/ssh/verifiers/always.rb +10 -4
- data/lib/net/ssh/verifiers/never.rb +4 -2
- data/lib/net/ssh/version.rb +2 -2
- data/lib/net/ssh.rb +17 -9
- data/net-ssh-public_cert.pem +18 -19
- data/net-ssh.gemspec +9 -7
- data/support/ssh_tunnel_bug.rb +3 -3
- data.tar.gz.sig +0 -0
- metadata +65 -41
- metadata.gz.sig +0 -0
- data/.travis.yml +0 -52
- data/Gemfile.noed25519.lock +0 -41
- data/README.rdoc +0 -169
- data/lib/net/ssh/ruby_compat.rb +0 -13
- data/support/arcfour_check.rb +0 -20
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
|
|
@@ -11,6 +10,7 @@ module Net
|
|
|
11
10
|
#
|
|
12
11
|
# * ChallengeResponseAuthentication => maps to the :auth_methods option challenge-response (then coleasced into keyboard-interactive)
|
|
13
12
|
# * KbdInteractiveAuthentication => maps to the :auth_methods keyboard-interactive
|
|
13
|
+
# * CertificateFile => maps to the :keycerts option
|
|
14
14
|
# * Ciphers => maps to the :encryption option
|
|
15
15
|
# * Compression => :compression
|
|
16
16
|
# * CompressionLevel => :compression_level
|
|
@@ -22,7 +22,9 @@ module Net
|
|
|
22
22
|
# * HostKeyAlias => :host_key_alias
|
|
23
23
|
# * HostName => :host_name
|
|
24
24
|
# * IdentityFile => maps to the :keys option
|
|
25
|
+
# * IdentityAgent => :identity_agent
|
|
25
26
|
# * IdentitiesOnly => :keys_only
|
|
27
|
+
# * CheckHostIP => :check_host_ip
|
|
26
28
|
# * Macs => maps to the :hmac option
|
|
27
29
|
# * PasswordAuthentication => maps to the :auth_methods option password
|
|
28
30
|
# * Port => :port
|
|
@@ -31,6 +33,7 @@ module Net
|
|
|
31
33
|
# * ProxyJump => maps to the :proxy option
|
|
32
34
|
# * PubKeyAuthentication => maps to the :auth_methods option
|
|
33
35
|
# * RekeyLimit => :rekey_limit
|
|
36
|
+
# * StrictHostKeyChecking => :verify_host_key
|
|
34
37
|
# * User => :user
|
|
35
38
|
# * UserKnownHostsFile => :user_known_hosts_file
|
|
36
39
|
# * NumberOfPasswordPrompts => :number_of_password_prompts
|
|
@@ -62,7 +65,7 @@ module Net
|
|
|
62
65
|
# given +files+ (defaulting to the list of files returned by
|
|
63
66
|
# #default_files), translates the resulting hash into the options
|
|
64
67
|
# recognized by Net::SSH, and returns them.
|
|
65
|
-
def for(host, files=expandable_default_files)
|
|
68
|
+
def for(host, files = expandable_default_files)
|
|
66
69
|
translate(files.inject({}) { |settings, file|
|
|
67
70
|
load(file, host, settings)
|
|
68
71
|
})
|
|
@@ -74,7 +77,7 @@ module Net
|
|
|
74
77
|
# ones. Returns a hash containing the OpenSSH options. (See
|
|
75
78
|
# #translate for how to convert the OpenSSH options into Net::SSH
|
|
76
79
|
# options.)
|
|
77
|
-
def load(path, host, settings={}, base_dir = nil)
|
|
80
|
+
def load(path, host, settings = {}, base_dir = nil)
|
|
78
81
|
file = File.expand_path(path)
|
|
79
82
|
base_dir ||= File.dirname(file)
|
|
80
83
|
return settings unless File.readable?(file)
|
|
@@ -95,7 +98,7 @@ module Net
|
|
|
95
98
|
next if value.nil?
|
|
96
99
|
|
|
97
100
|
key.downcase!
|
|
98
|
-
value =
|
|
101
|
+
value = unquote(value)
|
|
99
102
|
|
|
100
103
|
value = case value.strip
|
|
101
104
|
when /^\d+$/ then value.to_i
|
|
@@ -126,7 +129,7 @@ module Net
|
|
|
126
129
|
block_seen = true
|
|
127
130
|
elsif !block_seen
|
|
128
131
|
case key
|
|
129
|
-
when 'identityfile'
|
|
132
|
+
when 'identityfile', 'certificatefile'
|
|
130
133
|
(globals[key] ||= []) << value
|
|
131
134
|
when 'include'
|
|
132
135
|
included_file_paths(base_dir, value).each do |file_path|
|
|
@@ -137,7 +140,7 @@ module Net
|
|
|
137
140
|
end
|
|
138
141
|
elsif block_matched
|
|
139
142
|
case key
|
|
140
|
-
when 'identityfile'
|
|
143
|
+
when 'identityfile', 'certificatefile'
|
|
141
144
|
(settings[key] ||= []) << value
|
|
142
145
|
when 'include'
|
|
143
146
|
included_file_paths(base_dir, value).each do |file_path|
|
|
@@ -147,11 +150,18 @@ module Net
|
|
|
147
150
|
settings[key] = value unless settings.key?(key)
|
|
148
151
|
end
|
|
149
152
|
end
|
|
153
|
+
|
|
154
|
+
# ProxyCommand and ProxyJump override each other so they need to be tracked togeather
|
|
155
|
+
%w[proxyjump proxycommand].each do |proxy_key|
|
|
156
|
+
if (proxy_value = settings.delete(proxy_key))
|
|
157
|
+
settings['proxy'] ||= [proxy_key, proxy_value]
|
|
158
|
+
end
|
|
159
|
+
end
|
|
150
160
|
end
|
|
151
161
|
|
|
152
162
|
globals.merge(settings) do |key, oldval, newval|
|
|
153
163
|
case key
|
|
154
|
-
when 'identityfile'
|
|
164
|
+
when 'identityfile', 'certificatefile'
|
|
155
165
|
oldval + newval
|
|
156
166
|
else
|
|
157
167
|
newval
|
|
@@ -175,34 +185,57 @@ module Net
|
|
|
175
185
|
# Filters default_files down to the files that are expandable.
|
|
176
186
|
def expandable_default_files
|
|
177
187
|
default_files.keep_if do |path|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
false
|
|
183
|
-
end
|
|
188
|
+
File.expand_path(path)
|
|
189
|
+
true
|
|
190
|
+
rescue ArgumentError
|
|
191
|
+
false
|
|
184
192
|
end
|
|
185
193
|
end
|
|
186
194
|
|
|
187
195
|
private
|
|
188
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
|
+
|
|
217
|
+
TRANSLATE_CONFIG_KEY_RENAME_MAP = {
|
|
218
|
+
bindaddress: :bind_address,
|
|
219
|
+
compression: :compression,
|
|
220
|
+
compressionlevel: :compression_level,
|
|
221
|
+
certificatefile: :keycerts,
|
|
222
|
+
connecttimeout: :timeout,
|
|
223
|
+
forwardagent: :forward_agent,
|
|
224
|
+
identitiesonly: :keys_only,
|
|
225
|
+
identityagent: :identity_agent,
|
|
226
|
+
globalknownhostsfile: :global_known_hosts_file,
|
|
227
|
+
hostkeyalias: :host_key_alias,
|
|
228
|
+
identityfile: :keys,
|
|
229
|
+
fingerprinthash: :fingerprint_hash,
|
|
230
|
+
port: :port,
|
|
231
|
+
user: :user,
|
|
232
|
+
userknownhostsfile: :user_known_hosts_file,
|
|
233
|
+
checkhostip: :check_host_ip
|
|
234
|
+
}.freeze
|
|
189
235
|
def translate_config_key(hash, key, value, settings)
|
|
190
|
-
rename = {
|
|
191
|
-
bindaddress: :bind_address,
|
|
192
|
-
compression: :compression,
|
|
193
|
-
compressionlevel: :compression_level,
|
|
194
|
-
connecttimeout: :timeout,
|
|
195
|
-
forwardagent: :forward_agent,
|
|
196
|
-
identitiesonly: :keys_only,
|
|
197
|
-
globalknownhostsfile: :global_known_hosts_file,
|
|
198
|
-
hostkeyalias: :host_key_alias,
|
|
199
|
-
identityfile: :keys,
|
|
200
|
-
fingerprinthash: :fingerprint_hash,
|
|
201
|
-
port: :port,
|
|
202
|
-
user: :user,
|
|
203
|
-
userknownhostsfile: :user_known_hosts_file
|
|
204
|
-
}
|
|
205
236
|
case key
|
|
237
|
+
when :stricthostkeychecking
|
|
238
|
+
hash[:verify_host_key] = translate_verify_host_key(value)
|
|
206
239
|
when :ciphers
|
|
207
240
|
hash[:encryption] = value.split(/,/)
|
|
208
241
|
when :hostbasedauthentication
|
|
@@ -220,12 +253,7 @@ module Net
|
|
|
220
253
|
when :serveralivecountmax
|
|
221
254
|
hash[:keepalive_maxcount] = value.to_i if value
|
|
222
255
|
when :serveraliveinterval
|
|
223
|
-
|
|
224
|
-
hash[:keepalive] = true
|
|
225
|
-
hash[:keepalive_interval] = value.to_i
|
|
226
|
-
else
|
|
227
|
-
hash[:keepalive] = false
|
|
228
|
-
end
|
|
256
|
+
translate_keepalive(hash, value)
|
|
229
257
|
when :passwordauthentication
|
|
230
258
|
if value
|
|
231
259
|
(hash[:auth_methods] << 'password').uniq!
|
|
@@ -246,15 +274,9 @@ module Net
|
|
|
246
274
|
end
|
|
247
275
|
when :preferredauthentications
|
|
248
276
|
hash[:auth_methods] = value.split(/,/) # TODO we should place to preferred_auth_methods rather than auth_methods
|
|
249
|
-
when :
|
|
250
|
-
if
|
|
251
|
-
|
|
252
|
-
hash[:proxy] = Net::SSH::Proxy::Command.new(value)
|
|
253
|
-
end
|
|
254
|
-
when :proxyjump
|
|
255
|
-
if value
|
|
256
|
-
require 'net/ssh/proxy/jump'
|
|
257
|
-
hash[:proxy] = Net::SSH::Proxy::Jump.new(value)
|
|
277
|
+
when :proxy
|
|
278
|
+
if (proxy = setup_proxy(*value))
|
|
279
|
+
hash[:proxy] = proxy
|
|
258
280
|
end
|
|
259
281
|
when :pubkeyauthentication
|
|
260
282
|
if value
|
|
@@ -267,10 +289,25 @@ module Net
|
|
|
267
289
|
when :sendenv
|
|
268
290
|
multi_send_env = value.to_s.split(/\s+/)
|
|
269
291
|
hash[:send_env] = multi_send_env.map { |e| Regexp.new pattern2regex(e).source, false }
|
|
292
|
+
when :setenv
|
|
293
|
+
hash[:set_env] = Shellwords.split(value.to_s).map { |e| e.split '=', 2 }.to_h
|
|
270
294
|
when :numberofpasswordprompts
|
|
271
295
|
hash[:number_of_password_prompts] = value.to_i
|
|
272
|
-
when *
|
|
273
|
-
hash[
|
|
296
|
+
when *TRANSLATE_CONFIG_KEY_RENAME_MAP.keys
|
|
297
|
+
hash[TRANSLATE_CONFIG_KEY_RENAME_MAP[key]] = value
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def setup_proxy(type, value)
|
|
302
|
+
case type
|
|
303
|
+
when 'proxycommand'
|
|
304
|
+
if value !~ /^none$/
|
|
305
|
+
require 'net/ssh/proxy/command'
|
|
306
|
+
Net::SSH::Proxy::Command.new(value)
|
|
307
|
+
end
|
|
308
|
+
when 'proxyjump'
|
|
309
|
+
require 'net/ssh/proxy/jump'
|
|
310
|
+
Net::SSH::Proxy::Jump.new(value)
|
|
274
311
|
end
|
|
275
312
|
end
|
|
276
313
|
|
|
@@ -278,9 +315,9 @@ module Net
|
|
|
278
315
|
# host names.
|
|
279
316
|
def pattern2regex(pattern)
|
|
280
317
|
tail = pattern
|
|
281
|
-
prefix =
|
|
318
|
+
prefix = String.new
|
|
282
319
|
while !tail.empty? do
|
|
283
|
-
head,sep,tail = tail.partition(/[\*\?]/)
|
|
320
|
+
head, sep, tail = tail.partition(/[\*\?]/)
|
|
284
321
|
prefix = prefix + Regexp.quote(head)
|
|
285
322
|
case sep
|
|
286
323
|
when '*'
|
|
@@ -326,12 +363,17 @@ module Net
|
|
|
326
363
|
end
|
|
327
364
|
|
|
328
365
|
def eval_match_conditions(condition, host, settings)
|
|
329
|
-
|
|
366
|
+
# Not using `\s` for whitespace matching as canonical
|
|
367
|
+
# ssh_config parser implementation (OpenSSH) has specific character set.
|
|
368
|
+
# Ref: https://github.com/openssh/openssh-portable/blob/2581333d564d8697837729b3d07d45738eaf5a54/misc.c#L237-L239
|
|
369
|
+
conditions = condition.split(/[ \t\r\n]+|(?<!=)=(?!=)/).reject(&:empty?)
|
|
330
370
|
return true if conditions == ["all"]
|
|
331
371
|
|
|
332
372
|
conditions = conditions.each_slice(2)
|
|
333
|
-
|
|
334
|
-
conditions.each do |(kind,exprs)|
|
|
373
|
+
condition_matches = []
|
|
374
|
+
conditions.each do |(kind, exprs)|
|
|
375
|
+
exprs = unquote(exprs)
|
|
376
|
+
|
|
335
377
|
case kind.downcase
|
|
336
378
|
when "all"
|
|
337
379
|
raise "all cannot be mixed with other conditions"
|
|
@@ -346,15 +388,19 @@ module Net
|
|
|
346
388
|
exprs.split(",").each do |expr|
|
|
347
389
|
condition_met = condition_met || host =~ pattern2regex(expr)
|
|
348
390
|
end
|
|
349
|
-
|
|
391
|
+
condition_matches << (true && negated ^ condition_met)
|
|
350
392
|
# else
|
|
351
393
|
# warn "net-ssh: Unsupported expr in Match block: #{kind}"
|
|
352
394
|
end
|
|
353
395
|
end
|
|
354
|
-
|
|
396
|
+
|
|
397
|
+
!condition_matches.empty? && condition_matches.all?
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
def unquote(string)
|
|
401
|
+
string =~ /^"(.*)"$/ ? Regexp.last_match(1) : string
|
|
355
402
|
end
|
|
356
403
|
end
|
|
357
404
|
end
|
|
358
|
-
|
|
359
405
|
end
|
|
360
406
|
end
|