net-ssh-backports 6.3.0.backports
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 +7 -0
- data/.github/workflows/ci.yml +93 -0
- data/.gitignore +13 -0
- data/.rubocop.yml +21 -0
- data/.rubocop_todo.yml +1074 -0
- data/.travis.yml +51 -0
- data/CHANGES.txt +698 -0
- data/Gemfile +13 -0
- data/Gemfile.noed25519 +12 -0
- data/ISSUE_TEMPLATE.md +30 -0
- data/LICENSE.txt +19 -0
- data/Manifest +132 -0
- data/README.md +287 -0
- data/Rakefile +105 -0
- data/THANKS.txt +110 -0
- data/appveyor.yml +58 -0
- data/lib/net/ssh/authentication/agent.rb +284 -0
- data/lib/net/ssh/authentication/certificate.rb +183 -0
- data/lib/net/ssh/authentication/constants.rb +20 -0
- data/lib/net/ssh/authentication/ed25519.rb +185 -0
- data/lib/net/ssh/authentication/ed25519_loader.rb +31 -0
- data/lib/net/ssh/authentication/key_manager.rb +297 -0
- data/lib/net/ssh/authentication/methods/abstract.rb +69 -0
- data/lib/net/ssh/authentication/methods/hostbased.rb +72 -0
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +77 -0
- data/lib/net/ssh/authentication/methods/none.rb +34 -0
- data/lib/net/ssh/authentication/methods/password.rb +80 -0
- data/lib/net/ssh/authentication/methods/publickey.rb +95 -0
- data/lib/net/ssh/authentication/pageant.rb +497 -0
- data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
- data/lib/net/ssh/authentication/session.rb +163 -0
- data/lib/net/ssh/buffer.rb +434 -0
- data/lib/net/ssh/buffered_io.rb +202 -0
- data/lib/net/ssh/config.rb +406 -0
- data/lib/net/ssh/connection/channel.rb +695 -0
- data/lib/net/ssh/connection/constants.rb +33 -0
- data/lib/net/ssh/connection/event_loop.rb +123 -0
- data/lib/net/ssh/connection/keepalive.rb +59 -0
- data/lib/net/ssh/connection/session.rb +712 -0
- data/lib/net/ssh/connection/term.rb +180 -0
- data/lib/net/ssh/errors.rb +106 -0
- data/lib/net/ssh/key_factory.rb +218 -0
- data/lib/net/ssh/known_hosts.rb +264 -0
- data/lib/net/ssh/loggable.rb +62 -0
- data/lib/net/ssh/packet.rb +106 -0
- data/lib/net/ssh/prompt.rb +62 -0
- data/lib/net/ssh/proxy/command.rb +123 -0
- data/lib/net/ssh/proxy/errors.rb +16 -0
- data/lib/net/ssh/proxy/http.rb +98 -0
- data/lib/net/ssh/proxy/https.rb +50 -0
- data/lib/net/ssh/proxy/jump.rb +54 -0
- data/lib/net/ssh/proxy/socks4.rb +67 -0
- data/lib/net/ssh/proxy/socks5.rb +140 -0
- data/lib/net/ssh/service/forward.rb +426 -0
- data/lib/net/ssh/test/channel.rb +147 -0
- data/lib/net/ssh/test/extensions.rb +173 -0
- data/lib/net/ssh/test/kex.rb +46 -0
- data/lib/net/ssh/test/local_packet.rb +53 -0
- data/lib/net/ssh/test/packet.rb +101 -0
- data/lib/net/ssh/test/remote_packet.rb +40 -0
- data/lib/net/ssh/test/script.rb +180 -0
- data/lib/net/ssh/test/socket.rb +65 -0
- data/lib/net/ssh/test.rb +94 -0
- data/lib/net/ssh/transport/algorithms.rb +502 -0
- data/lib/net/ssh/transport/cipher_factory.rb +103 -0
- data/lib/net/ssh/transport/constants.rb +40 -0
- data/lib/net/ssh/transport/ctr.rb +115 -0
- data/lib/net/ssh/transport/hmac/abstract.rb +97 -0
- data/lib/net/ssh/transport/hmac/md5.rb +10 -0
- data/lib/net/ssh/transport/hmac/md5_96.rb +9 -0
- data/lib/net/ssh/transport/hmac/none.rb +13 -0
- data/lib/net/ssh/transport/hmac/ripemd160.rb +11 -0
- data/lib/net/ssh/transport/hmac/sha1.rb +11 -0
- data/lib/net/ssh/transport/hmac/sha1_96.rb +9 -0
- data/lib/net/ssh/transport/hmac/sha2_256.rb +11 -0
- data/lib/net/ssh/transport/hmac/sha2_256_96.rb +9 -0
- data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac/sha2_512.rb +11 -0
- data/lib/net/ssh/transport/hmac/sha2_512_96.rb +9 -0
- data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac.rb +47 -0
- data/lib/net/ssh/transport/identity_cipher.rb +57 -0
- 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 +37 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +122 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +72 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +11 -0
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +39 -0
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +21 -0
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +21 -0
- data/lib/net/ssh/transport/kex.rb +31 -0
- data/lib/net/ssh/transport/key_expander.rb +30 -0
- data/lib/net/ssh/transport/openssl.rb +253 -0
- data/lib/net/ssh/transport/packet_stream.rb +280 -0
- data/lib/net/ssh/transport/server_version.rb +77 -0
- data/lib/net/ssh/transport/session.rb +354 -0
- data/lib/net/ssh/transport/state.rb +208 -0
- data/lib/net/ssh/verifiers/accept_new.rb +33 -0
- data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
- data/lib/net/ssh/verifiers/always.rb +58 -0
- data/lib/net/ssh/verifiers/never.rb +19 -0
- data/lib/net/ssh/version.rb +68 -0
- data/lib/net/ssh.rb +330 -0
- data/net-ssh-public_cert.pem +20 -0
- data/net-ssh.gemspec +44 -0
- data/support/ssh_tunnel_bug.rb +65 -0
- metadata +271 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'net/ssh/prompt'
|
2
|
+
require 'net/ssh/authentication/methods/abstract'
|
3
|
+
|
4
|
+
module Net
|
5
|
+
module SSH
|
6
|
+
module Authentication
|
7
|
+
module Methods
|
8
|
+
# Implements the "keyboard-interactive" SSH authentication method.
|
9
|
+
class KeyboardInteractive < Abstract
|
10
|
+
USERAUTH_INFO_REQUEST = 60
|
11
|
+
USERAUTH_INFO_RESPONSE = 61
|
12
|
+
|
13
|
+
# Attempt to authenticate the given user for the given service.
|
14
|
+
def authenticate(next_service, username, password=nil)
|
15
|
+
debug { "trying keyboard-interactive" }
|
16
|
+
send_message(userauth_request(username, next_service, "keyboard-interactive", "", ""))
|
17
|
+
|
18
|
+
prompter = nil
|
19
|
+
loop do
|
20
|
+
message = session.next_message
|
21
|
+
|
22
|
+
case message.type
|
23
|
+
when USERAUTH_SUCCESS
|
24
|
+
debug { "keyboard-interactive succeeded" }
|
25
|
+
prompter.success if prompter
|
26
|
+
return true
|
27
|
+
when USERAUTH_FAILURE
|
28
|
+
debug { "keyboard-interactive failed" }
|
29
|
+
|
30
|
+
raise Net::SSH::Authentication::DisallowedMethod unless
|
31
|
+
message[:authentications].split(/,/).include? 'keyboard-interactive'
|
32
|
+
|
33
|
+
return false unless interactive?
|
34
|
+
|
35
|
+
password = nil
|
36
|
+
debug { "retrying keyboard-interactive" }
|
37
|
+
send_message(userauth_request(username, next_service, "keyboard-interactive", "", ""))
|
38
|
+
when USERAUTH_INFO_REQUEST
|
39
|
+
name = message.read_string
|
40
|
+
instruction = message.read_string
|
41
|
+
debug { "keyboard-interactive info request" }
|
42
|
+
|
43
|
+
if password.nil? && interactive? && prompter.nil?
|
44
|
+
prompter = prompt.start(type: 'keyboard-interactive', name: name, instruction: instruction)
|
45
|
+
end
|
46
|
+
|
47
|
+
_ = message.read_string # lang_tag
|
48
|
+
responses = []
|
49
|
+
|
50
|
+
message.read_long.times do
|
51
|
+
text = message.read_string
|
52
|
+
echo = message.read_bool
|
53
|
+
password_to_send = password || (prompter && prompter.ask(text, echo))
|
54
|
+
responses << password_to_send
|
55
|
+
end
|
56
|
+
|
57
|
+
# if the password failed the first time around, don't try
|
58
|
+
# and use it on subsequent requests.
|
59
|
+
password = nil
|
60
|
+
|
61
|
+
msg = Buffer.from(:byte, USERAUTH_INFO_RESPONSE, :long, responses.length, :string, responses)
|
62
|
+
send_message(msg)
|
63
|
+
else
|
64
|
+
raise Net::SSH::Exception, "unexpected reply in keyboard interactive: #{message.type} (#{message.inspect})"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def interactive?
|
70
|
+
options = session.transport.options || {}
|
71
|
+
!options[:non_interactive]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'net/ssh/errors'
|
2
|
+
require 'net/ssh/authentication/methods/abstract'
|
3
|
+
|
4
|
+
module Net
|
5
|
+
module SSH
|
6
|
+
module Authentication
|
7
|
+
module Methods
|
8
|
+
# Implements the "none" SSH authentication method.
|
9
|
+
class None < Abstract
|
10
|
+
# Attempt to authenticate as "none"
|
11
|
+
def authenticate(next_service, user="", password="")
|
12
|
+
send_message(userauth_request(user, next_service, "none"))
|
13
|
+
message = session.next_message
|
14
|
+
|
15
|
+
case message.type
|
16
|
+
when USERAUTH_SUCCESS
|
17
|
+
debug { "none succeeded" }
|
18
|
+
return true
|
19
|
+
when USERAUTH_FAILURE
|
20
|
+
debug { "none failed" }
|
21
|
+
|
22
|
+
raise Net::SSH::Authentication::DisallowedMethod unless
|
23
|
+
message[:authentications].split(/,/).include? 'none'
|
24
|
+
|
25
|
+
return false
|
26
|
+
else
|
27
|
+
raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'net/ssh/errors'
|
2
|
+
require 'net/ssh/prompt'
|
3
|
+
require 'net/ssh/authentication/methods/abstract'
|
4
|
+
|
5
|
+
module Net
|
6
|
+
module SSH
|
7
|
+
module Authentication
|
8
|
+
module Methods
|
9
|
+
# Implements the "password" SSH authentication method.
|
10
|
+
class Password < Abstract
|
11
|
+
# Attempt to authenticate the given user for the given service. If
|
12
|
+
# the password parameter is nil, this will ask for password
|
13
|
+
def authenticate(next_service, username, password=nil)
|
14
|
+
clear_prompter!
|
15
|
+
retries = 0
|
16
|
+
max_retries = get_max_retries
|
17
|
+
return false if !password && max_retries == 0
|
18
|
+
|
19
|
+
begin
|
20
|
+
password_to_send = password || ask_password(username)
|
21
|
+
|
22
|
+
send_message(userauth_request(username, next_service, "password", false, password_to_send))
|
23
|
+
message = session.next_message
|
24
|
+
retries += 1
|
25
|
+
|
26
|
+
if message.type == USERAUTH_FAILURE
|
27
|
+
debug { "password failed" }
|
28
|
+
|
29
|
+
raise Net::SSH::Authentication::DisallowedMethod unless
|
30
|
+
message[:authentications].split(/,/).include? 'password'
|
31
|
+
|
32
|
+
password = nil
|
33
|
+
end
|
34
|
+
end until (message.type != USERAUTH_FAILURE || retries >= max_retries)
|
35
|
+
|
36
|
+
case message.type
|
37
|
+
when USERAUTH_SUCCESS
|
38
|
+
debug { "password succeeded" }
|
39
|
+
@prompter.success if @prompter
|
40
|
+
return true
|
41
|
+
when USERAUTH_FAILURE
|
42
|
+
return false
|
43
|
+
when USERAUTH_PASSWD_CHANGEREQ
|
44
|
+
debug { "password change request received, failing" }
|
45
|
+
return false
|
46
|
+
else
|
47
|
+
raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
NUMBER_OF_PASSWORD_PROMPTS = 3
|
54
|
+
|
55
|
+
def clear_prompter!
|
56
|
+
@prompt_info = nil
|
57
|
+
@prompter = nil
|
58
|
+
end
|
59
|
+
|
60
|
+
def ask_password(username)
|
61
|
+
host = session.transport.host
|
62
|
+
prompt_info = { type: 'password', user: username, host: host }
|
63
|
+
if @prompt_info != prompt_info
|
64
|
+
@prompt_info = prompt_info
|
65
|
+
@prompter = prompt.start(prompt_info)
|
66
|
+
end
|
67
|
+
echo = false
|
68
|
+
@prompter.ask("#{username}@#{host}'s password:", echo)
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_max_retries
|
72
|
+
options = session.transport.options || {}
|
73
|
+
result = options[:number_of_password_prompts] || NUMBER_OF_PASSWORD_PROMPTS
|
74
|
+
options[:non_interactive] ? 0 : result
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'net/ssh/buffer'
|
2
|
+
require 'net/ssh/errors'
|
3
|
+
require 'net/ssh/authentication/methods/abstract'
|
4
|
+
|
5
|
+
module Net
|
6
|
+
module SSH
|
7
|
+
module Authentication
|
8
|
+
module Methods
|
9
|
+
# Implements the "publickey" SSH authentication method.
|
10
|
+
class Publickey < Abstract
|
11
|
+
# Attempts to perform public-key authentication for the given
|
12
|
+
# username, trying each identity known to the key manager. If any of
|
13
|
+
# them succeed, returns +true+, otherwise returns +false+. This
|
14
|
+
# requires the presence of a key manager.
|
15
|
+
def authenticate(next_service, username, password=nil)
|
16
|
+
return false unless key_manager
|
17
|
+
|
18
|
+
key_manager.each_identity do |identity|
|
19
|
+
return true if authenticate_with(identity, next_service, username)
|
20
|
+
end
|
21
|
+
|
22
|
+
return false
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# Builds a packet that contains the request formatted for sending
|
28
|
+
# a public-key request to the server.
|
29
|
+
def build_request(pub_key, username, next_service, has_sig)
|
30
|
+
blob = Net::SSH::Buffer.new
|
31
|
+
blob.write_key pub_key
|
32
|
+
|
33
|
+
userauth_request(username, next_service, "publickey", has_sig,
|
34
|
+
pub_key.ssh_type, blob.to_s)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Builds and sends a request formatted for a public-key
|
38
|
+
# authentication request.
|
39
|
+
def send_request(pub_key, username, next_service, signature=nil)
|
40
|
+
msg = build_request(pub_key, username, next_service, !signature.nil?)
|
41
|
+
msg.write_string(signature) if signature
|
42
|
+
send_message(msg)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Attempts to perform public-key authentication for the given
|
46
|
+
# username, with the given identity (public key). Returns +true+ if
|
47
|
+
# successful, or +false+ otherwise.
|
48
|
+
def authenticate_with(identity, next_service, username)
|
49
|
+
debug { "trying publickey (#{identity.fingerprint})" }
|
50
|
+
send_request(identity, username, next_service)
|
51
|
+
|
52
|
+
message = session.next_message
|
53
|
+
|
54
|
+
case message.type
|
55
|
+
when USERAUTH_PK_OK
|
56
|
+
buffer = build_request(identity, username, next_service, true)
|
57
|
+
sig_data = Net::SSH::Buffer.new
|
58
|
+
sig_data.write_string(session_id)
|
59
|
+
sig_data.append(buffer.to_s)
|
60
|
+
|
61
|
+
sig_blob = key_manager.sign(identity, sig_data)
|
62
|
+
|
63
|
+
send_request(identity, username, next_service, sig_blob.to_s)
|
64
|
+
message = session.next_message
|
65
|
+
|
66
|
+
case message.type
|
67
|
+
when USERAUTH_SUCCESS
|
68
|
+
debug { "publickey succeeded (#{identity.fingerprint})" }
|
69
|
+
return true
|
70
|
+
when USERAUTH_FAILURE
|
71
|
+
debug { "publickey failed (#{identity.fingerprint})" }
|
72
|
+
|
73
|
+
raise Net::SSH::Authentication::DisallowedMethod unless
|
74
|
+
message[:authentications].split(/,/).include? 'publickey'
|
75
|
+
|
76
|
+
return false
|
77
|
+
else
|
78
|
+
raise Net::SSH::Exception,
|
79
|
+
"unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
|
80
|
+
end
|
81
|
+
|
82
|
+
when USERAUTH_FAILURE
|
83
|
+
return false
|
84
|
+
when USERAUTH_SUCCESS
|
85
|
+
return true
|
86
|
+
|
87
|
+
else
|
88
|
+
raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|