net-ssh 7.3.6 → 8.0.2
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/.github/pull_request_template.md +1 -0
- data/.github/workflows/changelog.yml +43 -0
- data/.github/workflows/ci-with-docker.yml +0 -3
- data/.github/workflows/ci.yml +2 -17
- data/.github/workflows/rubocop.yml +3 -1
- data/.rubocop.yml +5 -1
- data/.rubocop_todo.yml +1 -7
- data/CHANGES.txt +82 -7
- data/CONTRIBUTING.md +35 -0
- data/Dockerfile +3 -3
- data/Dockerfile.openssl3 +1 -1
- data/Dockerfile.zlib_ng +1 -1
- data/README.md +71 -57
- data/Rakefile +66 -12
- data/appveyor.yml +4 -16
- data/changelog.d/README.md +1 -0
- data/docker-compose.yml +1 -7
- data/lib/net/ssh/authentication/agent.rb +35 -11
- data/lib/net/ssh/authentication/ed25519.rb +137 -44
- data/lib/net/ssh/authentication/ed25519_loader.rb +14 -9
- data/lib/net/ssh/authentication/key_manager.rb +22 -11
- data/lib/net/ssh/authentication/methods/abstract.rb +2 -8
- data/lib/net/ssh/authentication/methods/publickey.rb +3 -1
- data/lib/net/ssh/authentication/security_key.rb +71 -0
- data/lib/net/ssh/authentication/session.rb +29 -17
- data/lib/net/ssh/buffer.rb +6 -1
- data/lib/net/ssh/buffered_io.rb +40 -3
- data/lib/net/ssh/config.rb +28 -12
- data/lib/net/ssh/connection/channel.rb +49 -2
- data/lib/net/ssh/connection/session.rb +58 -8
- data/lib/net/ssh/errors.rb +24 -6
- data/lib/net/ssh/key_factory.rb +7 -1
- data/lib/net/ssh/known_hosts.rb +18 -8
- data/lib/net/ssh/multiplex/client.rb +162 -0
- data/lib/net/ssh/multiplex/control_path.rb +120 -0
- data/lib/net/ssh/multiplex/proxy_transport.rb +218 -0
- data/lib/net/ssh/multiplex.rb +126 -0
- data/lib/net/ssh/prompt.rb +3 -3
- data/lib/net/ssh/proxy/jump.rb +40 -2
- data/lib/net/ssh/service/forward.rb +35 -24
- data/lib/net/ssh/test.rb +2 -1
- data/lib/net/ssh/transport/algorithms.rb +88 -33
- data/lib/net/ssh/transport/chacha20_poly1305_cipher.rb +89 -16
- data/lib/net/ssh/transport/chacha20_poly1305_cipher_loader.rb +20 -1
- data/lib/net/ssh/transport/cipher_factory.rb +23 -1
- data/lib/net/ssh/transport/constants.rb +1 -0
- data/lib/net/ssh/transport/gcm_cipher.rb +27 -6
- data/lib/net/ssh/transport/hmac/sha1_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac.rb +2 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256.rb +41 -9
- data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +14 -6
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +8 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +45 -15
- data/lib/net/ssh/transport/openssl.rb +2 -1
- data/lib/net/ssh/transport/packet_stream.rb +12 -0
- data/lib/net/ssh/transport/session.rb +43 -45
- data/lib/net/ssh/verifiers/always.rb +0 -3
- data/lib/net/ssh/version.rb +3 -3
- data/lib/net/ssh.rb +141 -58
- data/net-ssh.gemspec +5 -8
- data/rakelib/changelog.rb +229 -0
- data.tar.gz.sig +0 -0
- metadata +37 -36
- metadata.gz.sig +0 -0
- data/Gemfile.noed25519 +0 -12
- data/Gemfile.norbnacl +0 -12
|
@@ -66,6 +66,7 @@ module Net
|
|
|
66
66
|
@port = options[:port] || DEFAULT_PORT
|
|
67
67
|
@bind_address = options[:bind_address] || nil
|
|
68
68
|
@options = options
|
|
69
|
+
@host_key_verifier = select_host_key_verifier(options[:verify_host_key])
|
|
69
70
|
|
|
70
71
|
@socket =
|
|
71
72
|
if (factory = options[:proxy])
|
|
@@ -79,21 +80,24 @@ module Net
|
|
|
79
80
|
|
|
80
81
|
@socket.extend(PacketStream)
|
|
81
82
|
@socket.logger = @logger
|
|
83
|
+
set_no_delay unless options[:no_delay] == false
|
|
82
84
|
|
|
83
85
|
debug { "connection established" }
|
|
84
86
|
|
|
85
87
|
@queue = []
|
|
86
88
|
@queued_bytes = 0
|
|
87
89
|
|
|
88
|
-
@host_key_verifier = select_host_key_verifier(options[:verify_host_key])
|
|
89
|
-
|
|
90
90
|
@server_version = ServerVersion.new(socket, logger, options[:timeout])
|
|
91
91
|
|
|
92
92
|
@algorithms = Algorithms.new(self, options)
|
|
93
93
|
@algorithms.start
|
|
94
94
|
wait { algorithms.initialized? }
|
|
95
95
|
rescue Errno::ETIMEDOUT
|
|
96
|
+
@socket&.close
|
|
96
97
|
raise Net::SSH::ConnectionTimeout
|
|
98
|
+
rescue StandardError
|
|
99
|
+
@socket&.close
|
|
100
|
+
raise
|
|
97
101
|
end
|
|
98
102
|
|
|
99
103
|
def host_keys
|
|
@@ -103,6 +107,10 @@ module Net
|
|
|
103
107
|
end
|
|
104
108
|
end
|
|
105
109
|
|
|
110
|
+
def pubkey_algorithms
|
|
111
|
+
algorithms[:pubkey_algorithms]
|
|
112
|
+
end
|
|
113
|
+
|
|
106
114
|
# Returns the host (and possibly IP address) in a format compatible with
|
|
107
115
|
# SSH known-host files.
|
|
108
116
|
def host_as_string
|
|
@@ -211,12 +219,17 @@ module Net
|
|
|
211
219
|
when DEBUG
|
|
212
220
|
send(packet[:always_display] ? :fatal : :debug) { packet[:message] }
|
|
213
221
|
|
|
222
|
+
# We don't advertise ext-info-c, but some servers send EXT_INFO anyway (#955).
|
|
223
|
+
when EXT_INFO
|
|
224
|
+
debug { "ignoring EXT_INFO packet" }
|
|
225
|
+
|
|
214
226
|
when KEXINIT
|
|
215
227
|
algorithms.accept_kexinit(packet)
|
|
216
228
|
|
|
217
229
|
else
|
|
218
230
|
return packet if algorithms.allow?(packet)
|
|
219
|
-
|
|
231
|
+
# Algorithms#rekey! clears initialized?, so the session id is what marks the first key exchange as done.
|
|
232
|
+
raise Net::SSH::Exception, "unexpected packet type #{packet.type} during initial key exchange" unless algorithms.session_id
|
|
220
233
|
|
|
221
234
|
push(packet)
|
|
222
235
|
end
|
|
@@ -293,23 +306,25 @@ module Net
|
|
|
293
306
|
packet
|
|
294
307
|
end
|
|
295
308
|
|
|
296
|
-
#
|
|
297
|
-
#
|
|
298
|
-
#
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
309
|
+
# Turns Nagle's algorithm off on the socket, so that a packet written
|
|
310
|
+
# while the previous one is still unacknowledged goes out right away
|
|
311
|
+
# instead of waiting for the server's ACK. A ProxyCommand hands the
|
|
312
|
+
# transport a pipe rather than a socket, and the command on its other
|
|
313
|
+
# end owns the TCP connection, so there is nothing to set in that case.
|
|
314
|
+
def set_no_delay
|
|
315
|
+
return unless socket.respond_to?(:setsockopt)
|
|
303
316
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
end
|
|
307
|
-
|
|
308
|
-
def verify_signature(&block)
|
|
309
|
-
yield
|
|
310
|
-
end
|
|
317
|
+
debug { "setting TCP_NODELAY" }
|
|
318
|
+
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
|
311
319
|
end
|
|
312
320
|
|
|
321
|
+
REMOVED_VERIFY_HOST_KEY_VALUES = {
|
|
322
|
+
false => :never,
|
|
323
|
+
true => :accept_new_or_local_tunnel,
|
|
324
|
+
very: :accept_new,
|
|
325
|
+
secure: :always
|
|
326
|
+
}.freeze
|
|
327
|
+
|
|
313
328
|
# Instantiates a new host-key verification class, based on the value of
|
|
314
329
|
# the parameter.
|
|
315
330
|
#
|
|
@@ -323,46 +338,29 @@ module Net
|
|
|
323
338
|
#
|
|
324
339
|
# If the argument happens to respond to :verify and :verify_signature,
|
|
325
340
|
# it is returned directly. Otherwise, an exception is raised.
|
|
326
|
-
#
|
|
327
|
-
# Values false, true, and :very were deprecated in
|
|
328
|
-
# [#595](https://github.com/net-ssh/net-ssh/pull/595)
|
|
329
341
|
def select_host_key_verifier(verifier)
|
|
330
342
|
case verifier
|
|
331
|
-
when false
|
|
332
|
-
Kernel.warn('verify_host_key: false is deprecated, use :never')
|
|
333
|
-
Net::SSH::Verifiers::Never.new
|
|
334
343
|
when :never then
|
|
335
344
|
Net::SSH::Verifiers::Never.new
|
|
336
|
-
when true
|
|
337
|
-
Kernel.warn('verify_host_key: true is deprecated, use :accept_new_or_local_tunnel')
|
|
338
|
-
Net::SSH::Verifiers::AcceptNewOrLocalTunnel.new
|
|
339
345
|
when :accept_new_or_local_tunnel, nil then
|
|
340
346
|
Net::SSH::Verifiers::AcceptNewOrLocalTunnel.new
|
|
341
|
-
when :very
|
|
342
|
-
Kernel.warn('verify_host_key: :very is deprecated, use :accept_new')
|
|
343
|
-
Net::SSH::Verifiers::AcceptNew.new
|
|
344
347
|
when :accept_new then
|
|
345
348
|
Net::SSH::Verifiers::AcceptNew.new
|
|
346
|
-
when :secure then
|
|
347
|
-
Kernel.warn('verify_host_key: :secure is deprecated, use :always')
|
|
348
|
-
Net::SSH::Verifiers::Always.new
|
|
349
349
|
when :always then
|
|
350
350
|
Net::SSH::Verifiers::Always.new
|
|
351
|
+
when *REMOVED_VERIFY_HOST_KEY_VALUES.keys
|
|
352
|
+
raise ArgumentError,
|
|
353
|
+
"verify_host_key: #{verifier.inspect} has been removed, use #{REMOVED_VERIFY_HOST_KEY_VALUES[verifier].inspect}"
|
|
351
354
|
else
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
end
|
|
359
|
-
else
|
|
360
|
-
raise(
|
|
361
|
-
ArgumentError,
|
|
362
|
-
"Invalid argument to :verify_host_key (or deprecated " \
|
|
363
|
-
":paranoid): #{verifier.inspect}"
|
|
364
|
-
)
|
|
355
|
+
raise ArgumentError, "Invalid argument to :verify_host_key: #{verifier.inspect}" unless verifier.respond_to?(:verify)
|
|
356
|
+
|
|
357
|
+
unless verifier.respond_to?(:verify_signature)
|
|
358
|
+
raise ArgumentError,
|
|
359
|
+
"verify_host_key verifier #{verifier.inspect} must implement verify_signature(&block): " \
|
|
360
|
+
"yield to the block, which checks the server's host key signature, and return its result"
|
|
365
361
|
end
|
|
362
|
+
|
|
363
|
+
verifier
|
|
366
364
|
end
|
|
367
365
|
end
|
|
368
366
|
end
|
|
@@ -51,9 +51,6 @@ module Net
|
|
|
51
51
|
# implement them (Net::SSH::HostKeyEntries::CertAuthority). Non-certificate
|
|
52
52
|
# entries do not respond to these predicates and are left untouched.
|
|
53
53
|
def verify_certificate!(entry, host_keys, arguments)
|
|
54
|
-
# Plain keys carry no certificate constraints, and respond_to? on this delegator prints a deprecation warning (#1026).
|
|
55
|
-
return if entry.is_a?(Net::SSH::HostKeyEntries::PubKey)
|
|
56
|
-
|
|
57
54
|
cert = arguments[:key]
|
|
58
55
|
|
|
59
56
|
if entry.respond_to?(:matches_validity?) && !entry.matches_validity?(cert)
|
data/lib/net/ssh/version.rb
CHANGED
|
@@ -46,13 +46,13 @@ module Net
|
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
# The major component of this version of the Net::SSH library
|
|
49
|
-
MAJOR =
|
|
49
|
+
MAJOR = 8
|
|
50
50
|
|
|
51
51
|
# The minor component of this version of the Net::SSH library
|
|
52
|
-
MINOR =
|
|
52
|
+
MINOR = 0
|
|
53
53
|
|
|
54
54
|
# The tiny component of this version of the Net::SSH library
|
|
55
|
-
TINY =
|
|
55
|
+
TINY = 2
|
|
56
56
|
|
|
57
57
|
# The prerelease component of this version of the Net::SSH library
|
|
58
58
|
# nil allowed
|
data/lib/net/ssh.rb
CHANGED
|
@@ -8,6 +8,7 @@ require 'net/ssh/loggable'
|
|
|
8
8
|
require 'net/ssh/transport/session'
|
|
9
9
|
require 'net/ssh/authentication/session'
|
|
10
10
|
require 'net/ssh/connection/session'
|
|
11
|
+
require 'net/ssh/multiplex'
|
|
11
12
|
require 'net/ssh/prompt'
|
|
12
13
|
|
|
13
14
|
module Net
|
|
@@ -62,14 +63,15 @@ module Net
|
|
|
62
63
|
auth_methods bind_address compression compression_level config
|
|
63
64
|
encryption forward_agent hmac host_key identity_agent remote_user
|
|
64
65
|
keepalive keepalive_interval keepalive_maxcount kex keys key_data
|
|
65
|
-
keycerts keycert_data languages logger
|
|
66
|
+
keycerts keycert_data languages logger password port proxy
|
|
66
67
|
rekey_blocks_limit rekey_limit rekey_packet_limit timeout verbose
|
|
67
68
|
known_hosts global_known_hosts_file user_known_hosts_file host_key_alias
|
|
68
69
|
host_name user properties passphrase keys_only max_pkt_size
|
|
69
70
|
max_win_size send_env set_env use_agent number_of_password_prompts
|
|
70
71
|
append_all_supported_algorithms non_interactive password_prompt
|
|
71
72
|
agent_socket_factory minimum_dh_bits verify_host_key
|
|
72
|
-
fingerprint_hash check_host_ip pubkey_algorithms
|
|
73
|
+
fingerprint_hash check_host_ip pubkey_algorithms no_delay
|
|
74
|
+
control_master control_path
|
|
73
75
|
]
|
|
74
76
|
|
|
75
77
|
# The standard means of starting a new SSH connection. When used with a
|
|
@@ -98,7 +100,10 @@ module Net
|
|
|
98
100
|
# ssh.loop
|
|
99
101
|
# end
|
|
100
102
|
#
|
|
101
|
-
# This method accepts the following options (all are optional)
|
|
103
|
+
# This method accepts the following options (all are optional). Omit an
|
|
104
|
+
# option to use its default or ssh_config value; passing +nil+ (or an array
|
|
105
|
+
# containing +nil+) raises ArgumentError, except for :password,
|
|
106
|
+
# :passphrase, :logger and :password_prompt, where +nil+ means the default.
|
|
102
107
|
#
|
|
103
108
|
# * :auth_methods => an array of authentication methods to try
|
|
104
109
|
# * :bind_address => the IP address on the connecting machine to use in
|
|
@@ -109,13 +114,48 @@ module Net
|
|
|
109
114
|
# * :compression => the compression algorithm to use, or +true+ to use
|
|
110
115
|
# whatever is supported.
|
|
111
116
|
# * :compression_level => the compression level to use when sending data
|
|
117
|
+
# * :control_master => set to +:auto+ to run the session through an
|
|
118
|
+
# already running OpenSSH ControlMaster for the same host, port and user
|
|
119
|
+
# (started e.g. with <tt>ssh -M</tt> or <tt>ControlMaster auto</tt>),
|
|
120
|
+
# using its proxy mode (OpenSSH 7.4 or later). This skips the TCP
|
|
121
|
+
# connection, key exchange and authentication. If there is no usable
|
|
122
|
+
# master (no ControlPath, no socket, refused, timed out, owned by another
|
|
123
|
+
# user) Net::SSH logs why and connects as usual; it never starts a master
|
|
124
|
+
# itself. The master's own settings then apply instead of the options
|
|
125
|
+
# for setting up a connection (:keys, :key_data, :password, :passphrase,
|
|
126
|
+
# :auth_methods, :verify_host_key, :known_hosts, :host_key, :kex,
|
|
127
|
+
# :encryption, :hmac, :compression, :rekey_*, :proxy, :keepalive and the
|
|
128
|
+
# like); explicitly passed ones are named at info level. Over the
|
|
129
|
+
# master, remote port forwarding (Service::Forward#remote and
|
|
130
|
+
# #cancel_remote) raises Net::SSH::NotSupportedOverControlMaster, as the
|
|
131
|
+
# master consumes the global request reply, so success, failure and the
|
|
132
|
+
# port allocated for port 0 can't be observed; other global requests
|
|
133
|
+
# raise it too. Agent and X11 forwarding requests raise it
|
|
134
|
+
# too, and :forward_agent is ignored (logged at info level), because the
|
|
135
|
+
# master serves them from its own agent or display only if it has
|
|
136
|
+
# ForwardAgent or ForwardX11 enabled itself, and rejects them otherwise.
|
|
137
|
+
# Keepalive and rekeying are left to the master. ssh_config's
|
|
138
|
+
# ControlMaster is ignored, only this option enables it. An invalid
|
|
139
|
+
# ControlPath raises ArgumentError. A missing or stale socket is logged
|
|
140
|
+
# at info level, a socket that can't be used (another owner, refused,
|
|
141
|
+
# wrong protocol, timed out) at warn level. Has no effect on Windows.
|
|
142
|
+
# Defaults to +false+.
|
|
143
|
+
# * :control_path => the ControlMaster socket to use with
|
|
144
|
+
# :control_master, with the same ~, ${ENV} and % tokens as ssh_config's
|
|
145
|
+
# ControlPath (%C, %d, %h, %i, %j, %k, %L, %l, %n, %p, %r, %u, %%).
|
|
146
|
+
# The master at that path decides which host and user the session is
|
|
147
|
+
# connected to, so a fixed path without %h, %p, %r or %C sends every
|
|
148
|
+
# host through the same master and the explicitly passed host key and
|
|
149
|
+
# authentication options are ignored. Defaults to ControlPath from
|
|
150
|
+
# ssh_config; +"none"+ disables the master.
|
|
112
151
|
# * :config => set to +true+ to load the default OpenSSH config files
|
|
113
152
|
# (~/.ssh/config, /etc/ssh_config), or to +false+ to not load them, or to
|
|
114
153
|
# a file-name (or array of file-names) to load those specific configuration
|
|
115
154
|
# files. Defaults to +true+.
|
|
116
155
|
# * :encryption => the encryption cipher (or ciphers) to use
|
|
117
156
|
# * :forward_agent => set to true if you want the SSH agent connection to
|
|
118
|
-
# be forwarded
|
|
157
|
+
# be forwarded. Ignored for a session through a ControlMaster (see
|
|
158
|
+
# :control_master).
|
|
119
159
|
# * :known_hosts => a custom object holding known hosts records.
|
|
120
160
|
# It must implement #search_for and `add` in a similiar manner as KnownHosts.
|
|
121
161
|
# * :global_known_hosts_file => the location of the global known hosts
|
|
@@ -137,7 +177,11 @@ module Net
|
|
|
137
177
|
# Defaults to +300+ seconds.
|
|
138
178
|
# * :keepalive_maxcount => the maximun number of keepalive packet miss allowed.
|
|
139
179
|
# Defaults to 3
|
|
140
|
-
# * :kex => the key exchange algorithm (or algorithms) to use
|
|
180
|
+
# * :kex => the key exchange algorithm (or algorithms) to use. Like
|
|
181
|
+
# KexAlgorithms, entries starting with +, - or ^ modify the default list.
|
|
182
|
+
# diffie-hellman-group14-sha1 is supported but not offered unless listed
|
|
183
|
+
# here (e.g. '+diffie-hellman-group14-sha1') or
|
|
184
|
+
# :append_all_supported_algorithms is set.
|
|
141
185
|
# * :keys => an array of file names of private keys to use for publickey
|
|
142
186
|
# and hostbased authentication
|
|
143
187
|
# * :keycerts => an array of file names of key certificates to use
|
|
@@ -155,12 +199,24 @@ module Net
|
|
|
155
199
|
# packet. Default is 0x8000 (32768 bytes). Increase to 0x10000 (65536 bytes)
|
|
156
200
|
# for better performance if your SSH server supports it (most do).
|
|
157
201
|
# * :max_win_size => maximum size we tell the other side that is supported for
|
|
158
|
-
# the window.
|
|
202
|
+
# the window, i.e. how much the server may send on a channel before net-ssh
|
|
203
|
+
# reads it. Default is 0x200000 (2 MB), as in OpenSSH. Smaller values limit
|
|
204
|
+
# how much data is in flight; some servers (e.g. Mikrotik) truncate output
|
|
205
|
+
# when the window is small.
|
|
206
|
+
# * :minimum_dh_bits => the smallest group, in bits, accepted from the server
|
|
207
|
+
# in diffie-hellman-group-exchange key exchange. Defaults to 2048, as in
|
|
208
|
+
# OpenSSH; lower it (e.g. to 1024) only to reach legacy servers that offer
|
|
209
|
+
# nothing larger.
|
|
210
|
+
# * :no_delay => turns Nagle's algorithm off on the connection's socket
|
|
211
|
+
# (TCP_NODELAY), so a packet written while the previous one is still
|
|
212
|
+
# unacknowledged is sent right away instead of waiting for the server's
|
|
213
|
+
# ACK. OpenSSH does the same for every connection. Set to +false+ to keep
|
|
214
|
+
# Nagle's algorithm on. Has no effect when the socket comes from a
|
|
215
|
+
# ProxyCommand, whose command owns the TCP connection. Defaults to +true+.
|
|
159
216
|
# * :non_interactive => set to true if your app is non interactive and prefers
|
|
160
217
|
# authentication failure vs password prompt. Non-interactive applications
|
|
161
218
|
# should set it to true to prefer failing a password/etc auth methods vs.
|
|
162
219
|
# asking for password.
|
|
163
|
-
# * :paranoid => deprecated alias for :verify_host_key
|
|
164
220
|
# * :passphrase => the passphrase to use when loading a private key (default
|
|
165
221
|
# is +nil+, for no passphrase)
|
|
166
222
|
# * :password => the password to use to login
|
|
@@ -168,11 +224,13 @@ module Net
|
|
|
168
224
|
# * :properties => a hash of key/value pairs to add to the new connection's
|
|
169
225
|
# properties (see Net::SSH::Connection::Session#properties)
|
|
170
226
|
# * :proxy => a proxy instance (see Proxy) to use when connecting
|
|
171
|
-
# * :pubkey_algorithms => the public key authentication algorithms to
|
|
172
|
-
#
|
|
173
|
-
#
|
|
174
|
-
#
|
|
175
|
-
#
|
|
227
|
+
# * :pubkey_algorithms => the public key authentication algorithms to offer,
|
|
228
|
+
# in order of preference (e.g. %w[ssh-ed25519 rsa-sha2-512 rsa-sha2-256]).
|
|
229
|
+
# Keys whose type isn't listed are skipped. Like PubkeyAcceptedAlgorithms,
|
|
230
|
+
# entries starting with +, - or ^ modify the default list. ssh-rsa (SHA-1),
|
|
231
|
+
# ssh-rsa-cert-v01@openssh.com and ssh-dss are supported but not offered
|
|
232
|
+
# unless listed here (e.g. '+ssh-rsa') or :append_all_supported_algorithms
|
|
233
|
+
# is set.
|
|
176
234
|
# * :rekey_blocks_limit => the max number of blocks to process before rekeying
|
|
177
235
|
# * :rekey_limit => the max number of bytes to process before rekeying
|
|
178
236
|
# * :rekey_packet_limit => the max number of packets to process before rekeying
|
|
@@ -184,7 +242,8 @@ module Net
|
|
|
184
242
|
# * :user => the user name to log in as; this overrides the +user+
|
|
185
243
|
# parameter, and is primarily only useful when provided via an SSH
|
|
186
244
|
# configuration file.
|
|
187
|
-
# * :remote_user => used for substitution into the '%r' part of a ProxyCommand
|
|
245
|
+
# * :remote_user => used for substitution into the '%r' part of a ProxyCommand;
|
|
246
|
+
# defaults to the user name the connection logs in as.
|
|
188
247
|
# * :user_known_hosts_file => the location of the user known hosts file.
|
|
189
248
|
# Set to an array to specify multiple user known hosts files.
|
|
190
249
|
# Defaults to %w(~/.ssh/known_hosts ~/.ssh/known_hosts2).
|
|
@@ -196,7 +255,9 @@ module Net
|
|
|
196
255
|
# default. The symbols :debug, :info, :warn, :error, and :fatal are also
|
|
197
256
|
# supported and are translated to the corresponding Logger constant.
|
|
198
257
|
# * :append_all_supported_algorithms => set to +true+ to append all supported
|
|
199
|
-
# algorithms by net-ssh
|
|
258
|
+
# algorithms by net-ssh, except the +none+ cipher and MAC, which must be
|
|
259
|
+
# named explicitly (e.g. encryption: '+none'). Was the default behaviour
|
|
260
|
+
# until 2.10
|
|
200
261
|
# * :number_of_password_prompts => Number of prompts for the password
|
|
201
262
|
# authentication method defaults to 3 set to 0 to disable prompt for
|
|
202
263
|
# password auth method
|
|
@@ -211,21 +272,32 @@ module Net
|
|
|
211
272
|
# * :accept_new_or_local_tunnel (insecure) ::Net::SSH::Verifiers::AcceptNewOrLocalTunnel
|
|
212
273
|
# * :accept_new (insecure) ::Net::SSH::Verifiers::AcceptNew
|
|
213
274
|
# * :always (secure) ::Net::SSH::Verifiers::Always
|
|
214
|
-
# You can also provide an own Object which responds to +verify
|
|
215
|
-
# given to +verify+ is a hash consisting
|
|
216
|
-
# the +:fingerprint+ and the +:session+.
|
|
217
|
-
# returning false declines it and
|
|
275
|
+
# You can also provide an own Object which responds to +verify+ and
|
|
276
|
+
# +verify_signature+. The argument given to +verify+ is a hash consisting
|
|
277
|
+
# of the +:key+, the +:key_blob+, the +:fingerprint+ and the +:session+.
|
|
278
|
+
# Returning true accepts the host key, returning false declines it and
|
|
279
|
+
# closes the connection. +verify_signature+ is given a block that checks
|
|
280
|
+
# the server's host key signature and must return the block's result.
|
|
218
281
|
# * :fingerprint_hash => 'MD5' or 'SHA256', defaults to 'SHA256'
|
|
219
282
|
# If +user+ parameter is nil it defaults to USER from ssh_config, or
|
|
220
283
|
# local username
|
|
221
284
|
def self.start(host, user = nil, options = {}, &block)
|
|
285
|
+
if options.key?(:paranoid)
|
|
286
|
+
raise ArgumentError, ":paranoid has been removed, use :verify_host_key (same values)"
|
|
287
|
+
end
|
|
288
|
+
|
|
222
289
|
invalid_options = options.keys - VALID_OPTIONS
|
|
223
290
|
if invalid_options.any?
|
|
224
291
|
raise ArgumentError, "invalid option(s): #{invalid_options.join(', ')}"
|
|
225
292
|
end
|
|
226
293
|
|
|
294
|
+
reject_nil_options(options)
|
|
295
|
+
Multiplex.validate_options!(options)
|
|
296
|
+
explicit_options = options.keys
|
|
297
|
+
host_arg = host
|
|
298
|
+
|
|
299
|
+
options = options.dup
|
|
227
300
|
assign_defaults(options)
|
|
228
|
-
_sanitize_options(options)
|
|
229
301
|
|
|
230
302
|
options[:user] = user if user
|
|
231
303
|
options = configuration_for(host, options.fetch(:config, true)).merge(options)
|
|
@@ -237,8 +309,6 @@ module Net
|
|
|
237
309
|
options[:number_of_password_prompts] = 0
|
|
238
310
|
end
|
|
239
311
|
|
|
240
|
-
_support_deprecated_option_paranoid(options)
|
|
241
|
-
|
|
242
312
|
if options[:verbose]
|
|
243
313
|
options[:logger].level = case options[:verbose]
|
|
244
314
|
when Integer then options[:verbose]
|
|
@@ -251,26 +321,35 @@ module Net
|
|
|
251
321
|
end
|
|
252
322
|
end
|
|
253
323
|
|
|
254
|
-
transport = Transport::Session.new(host, options)
|
|
255
|
-
auth = Authentication::Session.new(transport, options)
|
|
256
|
-
|
|
257
324
|
user = options.fetch(:user, user) || Etc.getpwuid.name
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
325
|
+
options[:remote_user] ||= user
|
|
326
|
+
|
|
327
|
+
connection = Multiplex.connect(host_arg, host, user, options, explicit: explicit_options) if options[:control_master]
|
|
328
|
+
connection ||= connect_directly(host, user, options)
|
|
329
|
+
|
|
330
|
+
if block_given?
|
|
331
|
+
begin
|
|
332
|
+
yield connection
|
|
333
|
+
ensure
|
|
334
|
+
connection.close unless connection.closed?
|
|
268
335
|
end
|
|
269
336
|
else
|
|
337
|
+
connection
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
def self.connect_directly(host, user, options)
|
|
342
|
+
transport = Transport::Session.new(host, options)
|
|
343
|
+
auth = Authentication::Session.new(transport, options)
|
|
344
|
+
|
|
345
|
+
unless auth.authenticate("ssh-connection", user, options[:password])
|
|
270
346
|
transport.close
|
|
271
347
|
raise AuthenticationFailed, "Authentication failed for user #{user}@#{host}"
|
|
272
348
|
end
|
|
349
|
+
|
|
350
|
+
Connection::Session.new(transport, options)
|
|
273
351
|
end
|
|
352
|
+
private_class_method :connect_directly
|
|
274
353
|
|
|
275
354
|
# Returns a hash of the configuration options for the given host, as read
|
|
276
355
|
# from the SSH configuration file(s). If +use_ssh_config+ is true (the
|
|
@@ -304,31 +383,35 @@ module Net
|
|
|
304
383
|
end
|
|
305
384
|
end
|
|
306
385
|
|
|
307
|
-
|
|
308
|
-
invalid_option_values = [nil, [nil]]
|
|
309
|
-
unless (options.values & invalid_option_values).empty?
|
|
310
|
-
nil_options = options.select { |_k, v| invalid_option_values.include?(v) }.map(&:first)
|
|
311
|
-
Kernel.warn "#{caller_locations(2, 1)[0]}: Passing nil, or [nil] to Net::SSH.start is deprecated for keys: #{nil_options.join(', ')}"
|
|
312
|
-
end
|
|
313
|
-
end
|
|
314
|
-
private_class_method :_sanitize_options
|
|
386
|
+
NIL_ALLOWED_OPTIONS = %i[password passphrase logger password_prompt].freeze
|
|
315
387
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
388
|
+
NIL_OPTION_HINTS = {
|
|
389
|
+
config: "config: false to skip ssh_config files",
|
|
390
|
+
proxy: "proxy: false to connect without a proxy",
|
|
391
|
+
keys: "keys: [] to use no key files",
|
|
392
|
+
use_agent: "use_agent: false to not use ssh-agent",
|
|
393
|
+
forward_agent: "forward_agent: false to not forward ssh-agent",
|
|
394
|
+
keepalive: "keepalive: false to send no keepalives",
|
|
395
|
+
compression: "compression: false to disable compression",
|
|
396
|
+
control_master: "control_master: false to not use a ControlMaster",
|
|
397
|
+
control_path: "control_path: 'none' to not use a ControlMaster socket",
|
|
398
|
+
send_env: "send_env: [] to send no environment variables",
|
|
399
|
+
set_env: "set_env: {} to set no environment variables"
|
|
400
|
+
}.freeze
|
|
401
|
+
private_constant :NIL_ALLOWED_OPTIONS, :NIL_OPTION_HINTS
|
|
402
|
+
|
|
403
|
+
def self.reject_nil_options(options)
|
|
404
|
+
nil_keys = options.select do |key, value|
|
|
405
|
+
!NIL_ALLOWED_OPTIONS.include?(key) && (value.nil? || (value.is_a?(Array) && value.include?(nil)))
|
|
406
|
+
end.keys
|
|
407
|
+
return if nil_keys.empty?
|
|
408
|
+
|
|
409
|
+
message = "nil is not allowed for #{nil_keys.map(&:inspect).join(', ')}; " \
|
|
410
|
+
"omit #{nil_keys.one? ? 'it' : 'them'} to use the default or ssh_config value"
|
|
411
|
+
hints = NIL_OPTION_HINTS.values_at(*nil_keys).compact
|
|
412
|
+
message += ", or pass #{hints.join(', or ')}" if hints.any?
|
|
413
|
+
raise ArgumentError, message
|
|
331
414
|
end
|
|
332
|
-
private_class_method :
|
|
415
|
+
private_class_method :reject_nil_options
|
|
333
416
|
end
|
|
334
417
|
end
|
data/net-ssh.gemspec
CHANGED
|
@@ -15,7 +15,7 @@ Gem::Specification.new do |spec|
|
|
|
15
15
|
spec.description = %q{Net::SSH: a pure-Ruby implementation of the SSH2 client protocol. It allows you to write programs that invoke and interact with processes on remote servers, via SSH2.}
|
|
16
16
|
spec.homepage = "https://github.com/net-ssh/net-ssh"
|
|
17
17
|
spec.license = "MIT"
|
|
18
|
-
spec.required_ruby_version = Gem::Requirement.new(">= 2.
|
|
18
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.7")
|
|
19
19
|
spec.metadata = {
|
|
20
20
|
"changelog_uri" => "https://github.com/net-ssh/net-ssh/blob/master/CHANGES.txt"
|
|
21
21
|
}
|
|
@@ -30,18 +30,15 @@ Gem::Specification.new do |spec|
|
|
|
30
30
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
31
31
|
spec.require_paths = ["lib"]
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
spec.add_development_dependency("ed25519", "~> 1.2")
|
|
36
|
-
spec.add_development_dependency('x25519') unless RUBY_PLATFORM == 'java'
|
|
37
|
-
end
|
|
33
|
+
spec.add_dependency("logger")
|
|
34
|
+
spec.add_dependency("openssl", ">= 3.2.0")
|
|
38
35
|
|
|
39
|
-
spec.add_development_dependency(
|
|
36
|
+
spec.add_development_dependency("bcrypt_pbkdf", "~> 1.0") unless RUBY_PLATFORM == "java"
|
|
40
37
|
|
|
41
38
|
spec.add_development_dependency "base64"
|
|
42
39
|
spec.add_development_dependency "bundler", ">= 1.17"
|
|
43
40
|
spec.add_development_dependency "minitest", "~> 5.19"
|
|
44
|
-
spec.add_development_dependency "mocha", "
|
|
41
|
+
spec.add_development_dependency "mocha", ">= 2.1", "< 4"
|
|
45
42
|
spec.add_development_dependency "ostruct"
|
|
46
43
|
spec.add_development_dependency "rake", "~> 12.0"
|
|
47
44
|
spec.add_development_dependency "rubocop", "~> 1.28.0"
|