net-ssh 6.1.0 → 7.3.0
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/FUNDING.yml +1 -0
- data/.github/config/rubocop_linter_action.yml +4 -0
- data/.github/workflows/ci-with-docker.yml +44 -0
- data/.github/workflows/ci.yml +94 -0
- data/.github/workflows/rubocop.yml +16 -0
- data/.gitignore +4 -0
- data/.rubocop.yml +12 -1
- data/.rubocop_todo.yml +475 -376
- data/CHANGES.txt +64 -3
- data/DEVELOPMENT.md +23 -0
- data/Dockerfile +29 -0
- data/Dockerfile.openssl3 +17 -0
- data/Gemfile +2 -0
- data/Gemfile.noed25519 +2 -0
- data/Gemfile.norbnacl +12 -0
- data/README.md +38 -22
- data/Rakefile +92 -0
- data/SECURITY.md +4 -0
- data/docker-compose.yml +25 -0
- data/lib/net/ssh/authentication/agent.rb +29 -13
- data/lib/net/ssh/authentication/certificate.rb +14 -11
- data/lib/net/ssh/authentication/constants.rb +0 -1
- data/lib/net/ssh/authentication/ed25519.rb +14 -11
- data/lib/net/ssh/authentication/ed25519_loader.rb +4 -7
- data/lib/net/ssh/authentication/key_manager.rb +65 -36
- 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 +2 -2
- 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 +57 -17
- data/lib/net/ssh/authentication/pageant.rb +97 -97
- data/lib/net/ssh/authentication/pub_key_fingerprint.rb +3 -3
- data/lib/net/ssh/authentication/session.rb +25 -17
- data/lib/net/ssh/buffer.rb +71 -51
- data/lib/net/ssh/buffered_io.rb +25 -26
- data/lib/net/ssh/config.rb +33 -20
- data/lib/net/ssh/connection/channel.rb +84 -82
- data/lib/net/ssh/connection/constants.rb +0 -4
- data/lib/net/ssh/connection/event_loop.rb +30 -24
- data/lib/net/ssh/connection/keepalive.rb +12 -12
- data/lib/net/ssh/connection/session.rb +109 -108
- data/lib/net/ssh/connection/term.rb +56 -58
- data/lib/net/ssh/errors.rb +12 -12
- data/lib/net/ssh/key_factory.rb +7 -8
- data/lib/net/ssh/known_hosts.rb +86 -18
- data/lib/net/ssh/loggable.rb +8 -9
- data/lib/net/ssh/packet.rb +1 -1
- data/lib/net/ssh/prompt.rb +9 -11
- data/lib/net/ssh/proxy/command.rb +1 -1
- 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 -5
- data/lib/net/ssh/service/forward.rb +7 -7
- data/lib/net/ssh/test/channel.rb +24 -26
- data/lib/net/ssh/test/extensions.rb +35 -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 +4 -5
- data/lib/net/ssh/transport/aes128_gcm.rb +40 -0
- data/lib/net/ssh/transport/aes256_gcm.rb +40 -0
- data/lib/net/ssh/transport/algorithms.rb +51 -19
- data/lib/net/ssh/transport/chacha20_poly1305_cipher.rb +117 -0
- data/lib/net/ssh/transport/chacha20_poly1305_cipher_loader.rb +17 -0
- data/lib/net/ssh/transport/cipher_factory.rb +56 -29
- data/lib/net/ssh/transport/constants.rb +3 -3
- data/lib/net/ssh/transport/ctr.rb +7 -7
- data/lib/net/ssh/transport/gcm_cipher.rb +207 -0
- 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.rb +12 -12
- data/lib/net/ssh/transport/identity_cipher.rb +19 -13
- data/lib/net/ssh/transport/kex/abstract.rb +12 -5
- data/lib/net/ssh/transport/kex/abstract5656.rb +1 -1
- data/lib/net/ssh/transport/kex/curve25519_sha256.rb +2 -1
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +4 -4
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +21 -21
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +1 -2
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +2 -2
- data/lib/net/ssh/transport/kex.rb +8 -6
- data/lib/net/ssh/transport/key_expander.rb +7 -8
- data/lib/net/ssh/transport/openssl.rb +51 -26
- data/lib/net/ssh/transport/openssl_cipher_extensions.rb +8 -0
- data/lib/net/ssh/transport/packet_stream.rb +46 -26
- data/lib/net/ssh/transport/server_version.rb +17 -16
- data/lib/net/ssh/transport/session.rb +9 -7
- data/lib/net/ssh/transport/state.rb +44 -44
- data/lib/net/ssh/verifiers/accept_new.rb +0 -2
- data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +1 -2
- data/lib/net/ssh/verifiers/always.rb +6 -4
- data/lib/net/ssh/verifiers/never.rb +0 -2
- data/lib/net/ssh/version.rb +2 -2
- data/lib/net/ssh.rb +15 -8
- data/net-ssh-public_cert.pem +19 -18
- data/net-ssh.gemspec +7 -4
- data/support/ssh_tunnel_bug.rb +3 -3
- data.tar.gz.sig +0 -0
- metadata +76 -29
- metadata.gz.sig +0 -0
- data/.travis.yml +0 -52
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
module Net
|
|
2
|
-
module SSH
|
|
1
|
+
module Net
|
|
2
|
+
module SSH
|
|
3
3
|
module Connection
|
|
4
|
-
|
|
5
4
|
# These constants are used when requesting a pseudo-terminal (via
|
|
6
5
|
# Net::SSH::Connection::Channel#request_pty). The descriptions for each are
|
|
7
6
|
# taken directly from RFC 4254 ("The Secure Shell (SSH) Connection Protocol"),
|
|
@@ -10,173 +9,172 @@ module Net
|
|
|
10
9
|
# Interrupt character; 255 if none. Similarly for the other characters.
|
|
11
10
|
# Not all of these characters are supported on all systems.
|
|
12
11
|
VINTR = 1
|
|
13
|
-
|
|
12
|
+
|
|
14
13
|
# The quit character (sends SIGQUIT signal on POSIX systems).
|
|
15
14
|
VQUIT = 2
|
|
16
|
-
|
|
15
|
+
|
|
17
16
|
# Erase the character to left of the cursor.
|
|
18
17
|
VERASE = 3
|
|
19
|
-
|
|
18
|
+
|
|
20
19
|
# Kill the current input line.
|
|
21
20
|
VKILL = 4
|
|
22
|
-
|
|
21
|
+
|
|
23
22
|
# End-of-file character (sends EOF from the terminal).
|
|
24
23
|
VEOF = 5
|
|
25
|
-
|
|
24
|
+
|
|
26
25
|
# End-of-line character in addition to carriage return and/or linefeed.
|
|
27
26
|
VEOL = 6
|
|
28
|
-
|
|
27
|
+
|
|
29
28
|
# Additional end-of-line character.
|
|
30
29
|
VEOL2 = 7
|
|
31
|
-
|
|
30
|
+
|
|
32
31
|
# Continues paused output (normally control-Q).
|
|
33
32
|
VSTART = 8
|
|
34
|
-
|
|
33
|
+
|
|
35
34
|
# Pauses output (normally control-S).
|
|
36
35
|
VSTOP = 9
|
|
37
|
-
|
|
36
|
+
|
|
38
37
|
# Suspends the current program.
|
|
39
38
|
VSUSP = 10
|
|
40
|
-
|
|
39
|
+
|
|
41
40
|
# Another suspend character.
|
|
42
41
|
VDSUSP = 11
|
|
43
|
-
|
|
42
|
+
|
|
44
43
|
# Reprints the current input line.
|
|
45
44
|
VREPRINT = 12
|
|
46
|
-
|
|
45
|
+
|
|
47
46
|
# Erases a word left of cursor.
|
|
48
47
|
VWERASE = 13
|
|
49
|
-
|
|
48
|
+
|
|
50
49
|
# Enter the next character typed literally, even if it is a special
|
|
51
50
|
# character.
|
|
52
51
|
VLNEXT = 14
|
|
53
|
-
|
|
52
|
+
|
|
54
53
|
# Character to flush output.
|
|
55
54
|
VFLUSH = 15
|
|
56
|
-
|
|
55
|
+
|
|
57
56
|
# Switch to a different shell layer.
|
|
58
57
|
VSWITCH = 16
|
|
59
|
-
|
|
58
|
+
|
|
60
59
|
# Prints system status line (load, command, pid, etc).
|
|
61
60
|
VSTATUS = 17
|
|
62
|
-
|
|
61
|
+
|
|
63
62
|
# Toggles the flushing of terminal output.
|
|
64
63
|
VDISCARD = 18
|
|
65
|
-
|
|
64
|
+
|
|
66
65
|
# The ignore parity flag. The parameter SHOULD be 0 if this flag is FALSE,
|
|
67
66
|
# and 1 if it is TRUE.
|
|
68
67
|
IGNPAR = 30
|
|
69
|
-
|
|
68
|
+
|
|
70
69
|
# Mark parity and framing errors.
|
|
71
70
|
PARMRK = 31
|
|
72
|
-
|
|
71
|
+
|
|
73
72
|
# Enable checking of parity errors.
|
|
74
73
|
INPCK = 32
|
|
75
|
-
|
|
74
|
+
|
|
76
75
|
# Strip 8th bit off characters.
|
|
77
76
|
ISTRIP = 33
|
|
78
|
-
|
|
77
|
+
|
|
79
78
|
# Map NL into CR on input.
|
|
80
79
|
INCLR = 34
|
|
81
|
-
|
|
80
|
+
|
|
82
81
|
# Ignore CR on input.
|
|
83
82
|
IGNCR = 35
|
|
84
|
-
|
|
83
|
+
|
|
85
84
|
# Map CR to NL on input.
|
|
86
85
|
ICRNL = 36
|
|
87
|
-
|
|
86
|
+
|
|
88
87
|
# Translate uppercase characters to lowercase.
|
|
89
88
|
IUCLC = 37
|
|
90
|
-
|
|
89
|
+
|
|
91
90
|
# Enable output flow control.
|
|
92
91
|
IXON = 38
|
|
93
|
-
|
|
92
|
+
|
|
94
93
|
# Any char will restart after stop.
|
|
95
94
|
IXANY = 39
|
|
96
|
-
|
|
95
|
+
|
|
97
96
|
# Enable input flow control.
|
|
98
97
|
IXOFF = 40
|
|
99
|
-
|
|
98
|
+
|
|
100
99
|
# Ring bell on input queue full.
|
|
101
100
|
IMAXBEL = 41
|
|
102
|
-
|
|
101
|
+
|
|
103
102
|
# Enable signals INTR, QUIT, [D]SUSP.
|
|
104
103
|
ISIG = 50
|
|
105
|
-
|
|
104
|
+
|
|
106
105
|
# Canonicalize input lines.
|
|
107
106
|
ICANON = 51
|
|
108
|
-
|
|
107
|
+
|
|
109
108
|
# Enable input and output of uppercase characters by preceding their
|
|
110
109
|
# lowercase equivalents with "\".
|
|
111
110
|
XCASE = 52
|
|
112
|
-
|
|
111
|
+
|
|
113
112
|
# Enable echoing.
|
|
114
113
|
ECHO = 53
|
|
115
|
-
|
|
114
|
+
|
|
116
115
|
# Visually erase chars.
|
|
117
116
|
ECHOE = 54
|
|
118
|
-
|
|
117
|
+
|
|
119
118
|
# Kill character discards current line.
|
|
120
119
|
ECHOK = 55
|
|
121
|
-
|
|
120
|
+
|
|
122
121
|
# Echo NL even if ECHO is off.
|
|
123
122
|
ECHONL = 56
|
|
124
|
-
|
|
123
|
+
|
|
125
124
|
# Don't flush after interrupt.
|
|
126
125
|
NOFLSH = 57
|
|
127
|
-
|
|
126
|
+
|
|
128
127
|
# Stop background jobs from output.
|
|
129
128
|
TOSTOP = 58
|
|
130
|
-
|
|
129
|
+
|
|
131
130
|
# Enable extensions.
|
|
132
131
|
IEXTEN = 59
|
|
133
|
-
|
|
132
|
+
|
|
134
133
|
# Echo control characters as ^(Char).
|
|
135
134
|
ECHOCTL = 60
|
|
136
|
-
|
|
135
|
+
|
|
137
136
|
# Visual erase for line kill.
|
|
138
137
|
ECHOKE = 61
|
|
139
|
-
|
|
138
|
+
|
|
140
139
|
# Retype pending input.
|
|
141
140
|
PENDIN = 62
|
|
142
|
-
|
|
141
|
+
|
|
143
142
|
# Enable output processing.
|
|
144
143
|
OPOST = 70
|
|
145
|
-
|
|
144
|
+
|
|
146
145
|
# Convert lowercase to uppercase.
|
|
147
146
|
OLCUC = 71
|
|
148
|
-
|
|
147
|
+
|
|
149
148
|
# Map NL to CR-NL.
|
|
150
149
|
ONLCR = 72
|
|
151
|
-
|
|
150
|
+
|
|
152
151
|
# Translate carriage return to newline (output).
|
|
153
152
|
OCRNL = 73
|
|
154
|
-
|
|
153
|
+
|
|
155
154
|
# Translate newline to carriage return-newline (output).
|
|
156
155
|
ONOCR = 74
|
|
157
|
-
|
|
156
|
+
|
|
158
157
|
# Newline performs a carriage return (output).
|
|
159
158
|
ONLRET = 75
|
|
160
|
-
|
|
159
|
+
|
|
161
160
|
# 7 bit mode.
|
|
162
161
|
CS7 = 90
|
|
163
|
-
|
|
162
|
+
|
|
164
163
|
# 8 bit mode.
|
|
165
164
|
CS8 = 91
|
|
166
|
-
|
|
165
|
+
|
|
167
166
|
# Parity enable.
|
|
168
167
|
PARENB = 92
|
|
169
|
-
|
|
168
|
+
|
|
170
169
|
# Odd parity, else even.
|
|
171
170
|
PARODD = 93
|
|
172
|
-
|
|
171
|
+
|
|
173
172
|
# Specifies the input baud rate in bits per second.
|
|
174
173
|
TTY_OP_ISPEED = 128
|
|
175
|
-
|
|
174
|
+
|
|
176
175
|
# Specifies the output baud rate in bits per second.
|
|
177
176
|
TTY_OP_OSPEED = 129
|
|
178
177
|
end
|
|
179
|
-
|
|
180
178
|
end
|
|
181
179
|
end
|
|
182
180
|
end
|
data/lib/net/ssh/errors.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
module Net
|
|
1
|
+
module Net
|
|
2
2
|
module SSH
|
|
3
3
|
# A general exception class, to act as the ancestor of all other Net::SSH
|
|
4
4
|
# exception classes.
|
|
@@ -33,7 +33,7 @@ module Net
|
|
|
33
33
|
# a "channel open failed" message.
|
|
34
34
|
class ChannelOpenFailed < Net::SSH::Exception
|
|
35
35
|
attr_reader :code, :reason
|
|
36
|
-
|
|
36
|
+
|
|
37
37
|
def initialize(code, reason)
|
|
38
38
|
@code, @reason = code, reason
|
|
39
39
|
super "#{reason} (#{code})"
|
|
@@ -45,43 +45,43 @@ module Net
|
|
|
45
45
|
# the remember_host! method on the exception, and then retry.
|
|
46
46
|
class HostKeyError < Net::SSH::Exception
|
|
47
47
|
# the callback to use when #remember_host! is called
|
|
48
|
-
attr_writer :callback
|
|
49
|
-
|
|
48
|
+
attr_writer :callback # :nodoc:
|
|
49
|
+
|
|
50
50
|
# situation-specific data describing the host (see #host, #port, etc.)
|
|
51
|
-
attr_writer :data
|
|
52
|
-
|
|
51
|
+
attr_writer :data # :nodoc:
|
|
52
|
+
|
|
53
53
|
# An accessor for getting at the data that was used to look up the host
|
|
54
54
|
# (see also #fingerprint, #host, #port, #ip, and #key).
|
|
55
55
|
def [](key)
|
|
56
56
|
@data && @data[key]
|
|
57
57
|
end
|
|
58
|
-
|
|
58
|
+
|
|
59
59
|
# Returns the fingerprint of the key for the host, which either was not
|
|
60
60
|
# found or did not match.
|
|
61
61
|
def fingerprint
|
|
62
62
|
@data && @data[:fingerprint]
|
|
63
63
|
end
|
|
64
|
-
|
|
64
|
+
|
|
65
65
|
# Returns the host name for the remote host, as reported by the socket.
|
|
66
66
|
def host
|
|
67
67
|
@data && @data[:peer] && @data[:peer][:host]
|
|
68
68
|
end
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
# Returns the port number for the remote host, as reported by the socket.
|
|
71
71
|
def port
|
|
72
72
|
@data && @data[:peer] && @data[:peer][:port]
|
|
73
73
|
end
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
# Returns the IP address of the remote host, as reported by the socket.
|
|
76
76
|
def ip
|
|
77
77
|
@data && @data[:peer] && @data[:peer][:ip]
|
|
78
78
|
end
|
|
79
|
-
|
|
79
|
+
|
|
80
80
|
# Returns the key itself, as reported by the remote host.
|
|
81
81
|
def key
|
|
82
82
|
@data && @data[:key]
|
|
83
83
|
end
|
|
84
|
-
|
|
84
|
+
|
|
85
85
|
# Tell Net::SSH to record this host and key in the known hosts file, so
|
|
86
86
|
# that subsequent connections will remember them.
|
|
87
87
|
def remember_host!
|
data/lib/net/ssh/key_factory.rb
CHANGED
|
@@ -5,7 +5,6 @@ require 'net/ssh/authentication/ed25519_loader'
|
|
|
5
5
|
|
|
6
6
|
module Net
|
|
7
7
|
module SSH
|
|
8
|
-
|
|
9
8
|
# A factory class for returning new Key classes. It is used for obtaining
|
|
10
9
|
# OpenSSL key instances via their SSH names, and for loading both public and
|
|
11
10
|
# private keys. It used used primarily by Net::SSH itself, internally, and
|
|
@@ -18,14 +17,14 @@ module Net
|
|
|
18
17
|
class KeyFactory
|
|
19
18
|
# Specifies the mapping of SSH names to OpenSSL key classes.
|
|
20
19
|
MAP = {
|
|
21
|
-
'dh'
|
|
22
|
-
'rsa'
|
|
23
|
-
'dsa'
|
|
20
|
+
'dh' => OpenSSL::PKey::DH,
|
|
21
|
+
'rsa' => OpenSSL::PKey::RSA,
|
|
22
|
+
'dsa' => OpenSSL::PKey::DSA,
|
|
24
23
|
'ecdsa' => OpenSSL::PKey::EC
|
|
25
24
|
}
|
|
26
25
|
MAP["ed25519"] = Net::SSH::Authentication::ED25519::PrivKey if defined? Net::SSH::Authentication::ED25519
|
|
27
26
|
|
|
28
|
-
class <<self
|
|
27
|
+
class << self
|
|
29
28
|
# Fetch an OpenSSL key instance by its SSH name. It will be a new,
|
|
30
29
|
# empty key of the given type.
|
|
31
30
|
def get(name)
|
|
@@ -37,7 +36,7 @@ module Net
|
|
|
37
36
|
# appropriately. The new key is returned. If the key itself is
|
|
38
37
|
# encrypted (requiring a passphrase to use), the user will be
|
|
39
38
|
# prompted to enter their password unless passphrase works.
|
|
40
|
-
def load_private_key(filename, passphrase=nil, ask_passphrase=true, prompt=Prompt.default)
|
|
39
|
+
def load_private_key(filename, passphrase = nil, ask_passphrase = true, prompt = Prompt.default)
|
|
41
40
|
data = File.read(File.expand_path(filename))
|
|
42
41
|
load_data_private_key(data, passphrase, ask_passphrase, filename, prompt)
|
|
43
42
|
end
|
|
@@ -47,7 +46,7 @@ module Net
|
|
|
47
46
|
# appropriately. The new key is returned. If the key itself is
|
|
48
47
|
# encrypted (requiring a passphrase to use), the user will be
|
|
49
48
|
# prompted to enter their password unless passphrase works.
|
|
50
|
-
def load_data_private_key(data, passphrase=nil, ask_passphrase=true, filename="", prompt=Prompt.default)
|
|
49
|
+
def load_data_private_key(data, passphrase = nil, ask_passphrase = true, filename = "", prompt = Prompt.default)
|
|
51
50
|
key_type = classify_key(data, filename)
|
|
52
51
|
|
|
53
52
|
encrypted_key = nil
|
|
@@ -87,7 +86,7 @@ module Net
|
|
|
87
86
|
# Loads a public key. It will correctly determine whether
|
|
88
87
|
# the file describes an RSA or DSA key, and will load it
|
|
89
88
|
# appropriately. The new public key is returned.
|
|
90
|
-
def load_data_public_key(data, filename="")
|
|
89
|
+
def load_data_public_key(data, filename = "")
|
|
91
90
|
fields = data.split(/ /)
|
|
92
91
|
|
|
93
92
|
blob = nil
|
data/lib/net/ssh/known_hosts.rb
CHANGED
|
@@ -1,11 +1,68 @@
|
|
|
1
1
|
require 'strscan'
|
|
2
2
|
require 'openssl'
|
|
3
|
-
require '
|
|
3
|
+
require 'delegate'
|
|
4
4
|
require 'net/ssh/buffer'
|
|
5
5
|
require 'net/ssh/authentication/ed25519_loader'
|
|
6
6
|
|
|
7
7
|
module Net
|
|
8
8
|
module SSH
|
|
9
|
+
module HostKeyEntries
|
|
10
|
+
# regular public key entry
|
|
11
|
+
class PubKey < Delegator
|
|
12
|
+
def initialize(key, comment: nil) # rubocop:disable Lint/MissingSuper
|
|
13
|
+
@key = key
|
|
14
|
+
@comment = comment
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def ssh_type
|
|
18
|
+
@key.ssh_type
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def ssh_types
|
|
22
|
+
[ssh_type]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_blob
|
|
26
|
+
@key.to_blob
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def __getobj__
|
|
30
|
+
Kernel.warn("Calling Net::SSH::Buffer methods on HostKeyEntries PubKey is deprecated")
|
|
31
|
+
@key
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def matches_key?(server_key)
|
|
35
|
+
@key.ssh_type == server_key.ssh_type && @key.to_blob == server_key.to_blob
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @cert-authority entry
|
|
40
|
+
class CertAuthority
|
|
41
|
+
def ssh_types
|
|
42
|
+
%w[
|
|
43
|
+
ecdsa-sha2-nistp256-cert-v01@openssh.com
|
|
44
|
+
ecdsa-sha2-nistp384-cert-v01@openssh.com
|
|
45
|
+
ecdsa-sha2-nistp521-cert-v01@openssh.com
|
|
46
|
+
ssh-ed25519-cert-v01@openssh.com
|
|
47
|
+
ssh-rsa-cert-v01@openssh.com
|
|
48
|
+
ssh-rsa-cert-v00@openssh.com
|
|
49
|
+
]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def initialize(key, comment: nil)
|
|
53
|
+
@key = key
|
|
54
|
+
@comment = comment
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def matches_key?(server_key)
|
|
58
|
+
if ssh_types.include?(server_key.ssh_type)
|
|
59
|
+
server_key.signature_valid? && (server_key.signature_key.to_blob == @key.to_blob)
|
|
60
|
+
else
|
|
61
|
+
false
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
9
66
|
|
|
10
67
|
# Represents the result of a search in known hosts
|
|
11
68
|
# see search_for
|
|
@@ -48,10 +105,10 @@ module Net
|
|
|
48
105
|
|
|
49
106
|
SUPPORTED_TYPE.push('ssh-ed25519') if Net::SSH::Authentication::ED25519Loader::LOADED
|
|
50
107
|
|
|
51
|
-
class <<self
|
|
108
|
+
class << self
|
|
52
109
|
# Searches all known host files (see KnownHosts.hostfiles) for all keys
|
|
53
110
|
# of the given host. Returns an enumerable of keys found.
|
|
54
|
-
def search_for(host, options={})
|
|
111
|
+
def search_for(host, options = {})
|
|
55
112
|
HostKeys.new(search_in(hostfiles(options), host, options), host, self, options)
|
|
56
113
|
end
|
|
57
114
|
|
|
@@ -70,7 +127,7 @@ module Net
|
|
|
70
127
|
#
|
|
71
128
|
# If you only want the user known host files, you can pass :user as
|
|
72
129
|
# the second option.
|
|
73
|
-
def hostfiles(options, which
|
|
130
|
+
def hostfiles(options, which = :all)
|
|
74
131
|
files = []
|
|
75
132
|
|
|
76
133
|
files += Array(options[:user_known_hosts_file] || %w[~/.ssh/known_hosts ~/.ssh/known_hosts2]) if which == :all || which == :user
|
|
@@ -85,14 +142,12 @@ module Net
|
|
|
85
142
|
# Looks in all user known host files (see KnownHosts.hostfiles) and tries to
|
|
86
143
|
# add an entry for the given host and key to the first file it is able
|
|
87
144
|
# to.
|
|
88
|
-
def add(host, key, options={})
|
|
145
|
+
def add(host, key, options = {})
|
|
89
146
|
hostfiles(options, :user).each do |file|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
# try the next hostfile
|
|
95
|
-
end
|
|
147
|
+
KnownHosts.new(file).add(host, key)
|
|
148
|
+
return
|
|
149
|
+
rescue SystemCallError
|
|
150
|
+
# try the next hostfile
|
|
96
151
|
end
|
|
97
152
|
end
|
|
98
153
|
end
|
|
@@ -130,7 +185,13 @@ module Net
|
|
|
130
185
|
|
|
131
186
|
File.open(source) do |file|
|
|
132
187
|
file.each_line do |line|
|
|
133
|
-
|
|
188
|
+
if line.start_with?('@')
|
|
189
|
+
marker, hosts, type, key_content, comment = line.split(' ')
|
|
190
|
+
else
|
|
191
|
+
marker = nil
|
|
192
|
+
hosts, type, key_content, comment = line.split(' ')
|
|
193
|
+
end
|
|
194
|
+
|
|
134
195
|
# Skip empty line or one that is commented
|
|
135
196
|
next if hosts.nil? || hosts.start_with?('#')
|
|
136
197
|
|
|
@@ -145,7 +206,14 @@ module Net
|
|
|
145
206
|
next unless found
|
|
146
207
|
|
|
147
208
|
blob = key_content.unpack("m*").first
|
|
148
|
-
|
|
209
|
+
raw_key = Net::SSH::Buffer.new(blob).read_key
|
|
210
|
+
|
|
211
|
+
keys <<
|
|
212
|
+
if marker == "@cert-authority"
|
|
213
|
+
HostKeyEntries::CertAuthority.new(raw_key, comment: comment)
|
|
214
|
+
else
|
|
215
|
+
HostKeyEntries::PubKey.new(raw_key, comment: comment)
|
|
216
|
+
end
|
|
149
217
|
end
|
|
150
218
|
end
|
|
151
219
|
|
|
@@ -155,11 +223,11 @@ module Net
|
|
|
155
223
|
def match(host, pattern)
|
|
156
224
|
if pattern.include?('*') || pattern.include?('?')
|
|
157
225
|
# see man 8 sshd for pattern details
|
|
158
|
-
pattern_regexp = pattern.split('*').map do |x|
|
|
159
|
-
x.split('?').map do |y|
|
|
226
|
+
pattern_regexp = pattern.split('*', -1).map do |x|
|
|
227
|
+
x.split('?', -1).map do |y|
|
|
160
228
|
Regexp.escape(y)
|
|
161
229
|
end.join('.')
|
|
162
|
-
end.join('
|
|
230
|
+
end.join('.*')
|
|
163
231
|
|
|
164
232
|
host =~ Regexp.new("\\A#{pattern_regexp}\\z")
|
|
165
233
|
else
|
|
@@ -172,11 +240,11 @@ module Net
|
|
|
172
240
|
def known_host_hash?(hostlist, entries)
|
|
173
241
|
if hostlist.size == 1 && hostlist.first =~ /\A\|1(\|.+){2}\z/
|
|
174
242
|
chunks = hostlist.first.split(/\|/)
|
|
175
|
-
salt =
|
|
243
|
+
salt = chunks[2].unpack1("m")
|
|
176
244
|
digest = OpenSSL::Digest.new('sha1')
|
|
177
245
|
entries.each do |entry|
|
|
178
246
|
hmac = OpenSSL::HMAC.digest(digest, salt, entry)
|
|
179
|
-
return true if
|
|
247
|
+
return true if [hmac].pack("m").chomp == chunks[3]
|
|
180
248
|
end
|
|
181
249
|
end
|
|
182
250
|
false
|
data/lib/net/ssh/loggable.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
module Net
|
|
1
|
+
module Net
|
|
2
2
|
module SSH
|
|
3
|
-
|
|
4
3
|
# A simple module to make logging easier to deal with. It assumes that the
|
|
5
4
|
# logger instance (if not nil) quacks like a Logger object (in Ruby's
|
|
6
5
|
# standard library). Although used primarily internally by Net::SSH, it
|
|
@@ -19,39 +18,39 @@ module Net
|
|
|
19
18
|
# The logger instance that will be used to log messages. If nil, nothing
|
|
20
19
|
# will be logged.
|
|
21
20
|
attr_accessor :logger
|
|
22
|
-
|
|
21
|
+
|
|
23
22
|
# Displays the result of yielding if the log level is Logger::DEBUG or
|
|
24
23
|
# greater.
|
|
25
24
|
def debug
|
|
26
25
|
logger.add(Logger::DEBUG, nil, facility) { yield } if logger && logger.debug?
|
|
27
26
|
end
|
|
28
|
-
|
|
27
|
+
|
|
29
28
|
# Displays the result of yielding if the log level is Logger::INFO or
|
|
30
29
|
# greater.
|
|
31
30
|
def info
|
|
32
31
|
logger.add(Logger::INFO, nil, facility) { yield } if logger && logger.info?
|
|
33
32
|
end
|
|
34
|
-
|
|
33
|
+
|
|
35
34
|
# Displays the result of yielding if the log level is Logger::WARN or
|
|
36
35
|
# greater. (Called lwarn to avoid shadowing with Kernel#warn.)
|
|
37
36
|
def lwarn
|
|
38
37
|
logger.add(Logger::WARN, nil, facility) { yield } if logger && logger.warn?
|
|
39
38
|
end
|
|
40
|
-
|
|
39
|
+
|
|
41
40
|
# Displays the result of yielding if the log level is Logger:ERROR or
|
|
42
41
|
# greater.
|
|
43
42
|
def error
|
|
44
43
|
logger.add(Logger::ERROR, nil, facility) { yield } if logger && logger.error?
|
|
45
44
|
end
|
|
46
|
-
|
|
45
|
+
|
|
47
46
|
# Displays the result of yielding if the log level is Logger::FATAL or
|
|
48
47
|
# greater.
|
|
49
48
|
def fatal
|
|
50
49
|
logger.add(Logger::FATAL, nil, facility) { yield } if logger && logger.fatal?
|
|
51
50
|
end
|
|
52
|
-
|
|
51
|
+
|
|
53
52
|
private
|
|
54
|
-
|
|
53
|
+
|
|
55
54
|
# Sets the "facility" value, used for reporting where a log message
|
|
56
55
|
# originates. It defaults to the name of class with the object_id
|
|
57
56
|
# appended.
|
data/lib/net/ssh/packet.rb
CHANGED
|
@@ -5,7 +5,6 @@ require 'net/ssh/connection/constants'
|
|
|
5
5
|
|
|
6
6
|
module Net
|
|
7
7
|
module SSH
|
|
8
|
-
|
|
9
8
|
# A specialization of Buffer that knows the format of certain common
|
|
10
9
|
# packet types. It auto-parses those packet types, and allows them to
|
|
11
10
|
# be accessed via the #[] accessor.
|
|
@@ -85,6 +84,7 @@ module Net
|
|
|
85
84
|
def [](name)
|
|
86
85
|
name = name.to_sym
|
|
87
86
|
raise ArgumentError, "no such element #{name}" unless @named_elements.key?(name)
|
|
87
|
+
|
|
88
88
|
@named_elements[name]
|
|
89
89
|
end
|
|
90
90
|
|
data/lib/net/ssh/prompt.rb
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
require 'io/console'
|
|
2
2
|
|
|
3
|
-
module Net
|
|
3
|
+
module Net
|
|
4
4
|
module SSH
|
|
5
|
-
|
|
6
5
|
# Default prompt implementation, called for asking password from user.
|
|
7
6
|
# It will never be instantiated directly, but will instead be created for
|
|
8
7
|
# you automatically.
|
|
@@ -13,8 +12,8 @@ module Net
|
|
|
13
12
|
#
|
|
14
13
|
# prompter = options[:password_prompt].start({type:'password'})
|
|
15
14
|
# while !ok && max_retries < 3
|
|
16
|
-
# user = prompter.ask("user: ",
|
|
17
|
-
# password = prompter.ask("password: ",
|
|
15
|
+
# user = prompter.ask("user: ", true)
|
|
16
|
+
# password = prompter.ask("password: ", false)
|
|
18
17
|
# ok = send(user, password)
|
|
19
18
|
# prompter.sucess if ok
|
|
20
19
|
# end
|
|
@@ -24,9 +23,9 @@ module Net
|
|
|
24
23
|
def self.default(options = {})
|
|
25
24
|
@default ||= new(options)
|
|
26
25
|
end
|
|
27
|
-
|
|
26
|
+
|
|
28
27
|
def initialize(options = {}); end
|
|
29
|
-
|
|
28
|
+
|
|
30
29
|
# default prompt object implementation. More sophisticated implemenetations
|
|
31
30
|
# might implement caching.
|
|
32
31
|
class Prompter
|
|
@@ -36,22 +35,22 @@ module Net
|
|
|
36
35
|
$stdout.puts(info[:instruction]) unless info[:instruction].empty?
|
|
37
36
|
end
|
|
38
37
|
end
|
|
39
|
-
|
|
38
|
+
|
|
40
39
|
# ask input from user, a prompter might ask for multiple inputs
|
|
41
40
|
# (like user and password) in a single session.
|
|
42
|
-
def ask(prompt, echo=true)
|
|
41
|
+
def ask(prompt, echo = true)
|
|
43
42
|
$stdout.print(prompt)
|
|
44
43
|
$stdout.flush
|
|
45
44
|
ret = $stdin.noecho(&:gets).chomp
|
|
46
45
|
$stdout.print("\n")
|
|
47
46
|
ret
|
|
48
47
|
end
|
|
49
|
-
|
|
48
|
+
|
|
50
49
|
# success method will be called when the password was accepted
|
|
51
50
|
# It's a good time to save password asked to a cache.
|
|
52
51
|
def success; end
|
|
53
52
|
end
|
|
54
|
-
|
|
53
|
+
|
|
55
54
|
# start password session. Multiple questions might be asked multiple times
|
|
56
55
|
# on the returned object. Info hash tries to uniquely identify the password
|
|
57
56
|
# session, so caching implementations can save passwords properly.
|
|
@@ -59,6 +58,5 @@ module Net
|
|
|
59
58
|
Prompter.new(info)
|
|
60
59
|
end
|
|
61
60
|
end
|
|
62
|
-
|
|
63
61
|
end
|
|
64
62
|
end
|
|
@@ -5,7 +5,6 @@ require 'net/ssh/proxy/errors'
|
|
|
5
5
|
module Net
|
|
6
6
|
module SSH
|
|
7
7
|
module Proxy
|
|
8
|
-
|
|
9
8
|
# An implementation of a command proxy. To use it, instantiate it,
|
|
10
9
|
# then pass the instantiated object via the :proxy key to
|
|
11
10
|
# Net::SSH.start:
|
|
@@ -105,6 +104,7 @@ module Net
|
|
|
105
104
|
if IO.select([self], nil, [self], timeout_in_seconds) == nil
|
|
106
105
|
raise "Unexpected spurious read wakeup"
|
|
107
106
|
end
|
|
107
|
+
|
|
108
108
|
retry
|
|
109
109
|
end
|
|
110
110
|
result
|