net-ssh 2.9.2 → 4.0.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/.gitignore +6 -0
- data/.rubocop.yml +5 -0
- data/.rubocop_todo.yml +1129 -0
- data/.travis.yml +41 -5
- data/CHANGES.txt +133 -1
- data/Gemfile +13 -0
- data/Gemfile.norbnacl +10 -0
- data/Gemfile.norbnacl.lock +41 -0
- data/ISSUE_TEMPLATE.md +30 -0
- data/README.rdoc +26 -81
- data/Rakefile +63 -45
- data/appveyor.yml +51 -0
- data/lib/net/ssh/authentication/agent.rb +174 -14
- data/lib/net/ssh/authentication/ed25519.rb +137 -0
- data/lib/net/ssh/authentication/ed25519_loader.rb +21 -0
- data/lib/net/ssh/authentication/key_manager.rb +36 -30
- data/lib/net/ssh/authentication/methods/abstract.rb +4 -0
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +16 -9
- data/lib/net/ssh/authentication/methods/password.rb +17 -4
- data/lib/net/ssh/authentication/pageant.rb +166 -45
- data/lib/net/ssh/authentication/session.rb +3 -2
- data/lib/net/ssh/buffer.rb +49 -10
- data/lib/net/ssh/buffered_io.rb +17 -12
- data/lib/net/ssh/config.rb +39 -8
- data/lib/net/ssh/connection/channel.rb +42 -20
- data/lib/net/ssh/connection/event_loop.rb +114 -0
- data/lib/net/ssh/connection/keepalive.rb +2 -2
- data/lib/net/ssh/connection/session.rb +120 -34
- data/lib/net/ssh/errors.rb +6 -6
- data/lib/net/ssh/key_factory.rb +49 -43
- data/lib/net/ssh/known_hosts.rb +49 -3
- data/lib/net/ssh/prompt.rb +47 -78
- data/lib/net/ssh/proxy/command.rb +31 -5
- data/lib/net/ssh/proxy/http.rb +15 -11
- data/lib/net/ssh/proxy/https.rb +49 -0
- 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 +2 -29
- data/lib/net/ssh/service/forward.rb +2 -2
- data/lib/net/ssh/test/channel.rb +7 -0
- data/lib/net/ssh/test/extensions.rb +17 -0
- data/lib/net/ssh/test/kex.rb +4 -4
- data/lib/net/ssh/test/packet.rb +18 -2
- data/lib/net/ssh/test/script.rb +16 -2
- data/lib/net/ssh/test/socket.rb +1 -1
- data/lib/net/ssh/test.rb +5 -5
- data/lib/net/ssh/transport/algorithms.rb +92 -75
- data/lib/net/ssh/transport/cipher_factory.rb +19 -26
- data/lib/net/ssh/transport/ctr.rb +7 -9
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +20 -9
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +5 -3
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +1 -1
- data/lib/net/ssh/transport/key_expander.rb +1 -0
- data/lib/net/ssh/transport/openssl.rb +1 -1
- data/lib/net/ssh/transport/packet_stream.rb +11 -3
- data/lib/net/ssh/transport/server_version.rb +13 -6
- data/lib/net/ssh/transport/session.rb +20 -10
- data/lib/net/ssh/transport/state.rb +1 -1
- data/lib/net/ssh/verifiers/secure.rb +8 -10
- data/lib/net/ssh/version.rb +4 -4
- data/lib/net/ssh.rb +62 -14
- data/net-ssh-public_cert.pem +19 -18
- data/net-ssh.gemspec +34 -194
- data/support/arcfour_check.rb +1 -1
- data/support/ssh_tunnel_bug.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +125 -109
- metadata.gz.sig +0 -0
- data/Rudyfile +0 -96
- data/lib/net/ssh/authentication/agent/java_pageant.rb +0 -85
- data/lib/net/ssh/authentication/agent/socket.rb +0 -178
- data/setup.rb +0 -1585
- data/test/README.txt +0 -47
- data/test/authentication/methods/common.rb +0 -28
- data/test/authentication/methods/test_abstract.rb +0 -51
- data/test/authentication/methods/test_hostbased.rb +0 -114
- data/test/authentication/methods/test_keyboard_interactive.rb +0 -100
- data/test/authentication/methods/test_none.rb +0 -41
- data/test/authentication/methods/test_password.rb +0 -95
- data/test/authentication/methods/test_publickey.rb +0 -148
- data/test/authentication/test_agent.rb +0 -224
- data/test/authentication/test_key_manager.rb +0 -227
- data/test/authentication/test_session.rb +0 -107
- data/test/common.rb +0 -108
- data/test/configs/auth_off +0 -5
- data/test/configs/auth_on +0 -4
- data/test/configs/empty +0 -0
- data/test/configs/eqsign +0 -3
- data/test/configs/exact_match +0 -8
- data/test/configs/host_plus +0 -10
- data/test/configs/multihost +0 -4
- data/test/configs/negative_match +0 -6
- data/test/configs/nohost +0 -19
- data/test/configs/numeric_host +0 -4
- data/test/configs/send_env +0 -2
- data/test/configs/substitutes +0 -8
- data/test/configs/wild_cards +0 -14
- data/test/connection/test_channel.rb +0 -467
- data/test/connection/test_session.rb +0 -543
- data/test/known_hosts/github +0 -1
- data/test/manual/test_forward.rb +0 -285
- data/test/manual/test_pageant.rb +0 -37
- data/test/start/test_connection.rb +0 -53
- data/test/start/test_options.rb +0 -43
- data/test/start/test_transport.rb +0 -28
- data/test/test_all.rb +0 -11
- data/test/test_buffer.rb +0 -433
- data/test/test_buffered_io.rb +0 -63
- data/test/test_config.rb +0 -221
- data/test/test_key_factory.rb +0 -191
- data/test/test_known_hosts.rb +0 -13
- data/test/transport/hmac/test_md5.rb +0 -41
- data/test/transport/hmac/test_md5_96.rb +0 -27
- data/test/transport/hmac/test_none.rb +0 -34
- data/test/transport/hmac/test_ripemd160.rb +0 -36
- data/test/transport/hmac/test_sha1.rb +0 -36
- data/test/transport/hmac/test_sha1_96.rb +0 -27
- data/test/transport/hmac/test_sha2_256.rb +0 -37
- data/test/transport/hmac/test_sha2_256_96.rb +0 -27
- data/test/transport/hmac/test_sha2_512.rb +0 -37
- data/test/transport/hmac/test_sha2_512_96.rb +0 -27
- data/test/transport/kex/test_diffie_hellman_group14_sha1.rb +0 -13
- data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +0 -146
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +0 -92
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +0 -34
- data/test/transport/kex/test_ecdh_sha2_nistp256.rb +0 -161
- data/test/transport/kex/test_ecdh_sha2_nistp384.rb +0 -38
- data/test/transport/kex/test_ecdh_sha2_nistp521.rb +0 -38
- data/test/transport/test_algorithms.rb +0 -324
- data/test/transport/test_cipher_factory.rb +0 -443
- data/test/transport/test_hmac.rb +0 -34
- data/test/transport/test_identity_cipher.rb +0 -40
- data/test/transport/test_packet_stream.rb +0 -1761
- data/test/transport/test_server_version.rb +0 -78
- data/test/transport/test_session.rb +0 -331
- data/test/transport/test_state.rb +0 -181
|
@@ -1,10 +1,22 @@
|
|
|
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
|
+
if RUBY_PLATFORM != "java"
|
|
17
|
+
RUBY_FREE ||= Fiddle::RUBY_FREE
|
|
18
|
+
end
|
|
19
|
+
end
|
|
8
20
|
end
|
|
9
21
|
|
|
10
22
|
require 'net/ssh/errors'
|
|
@@ -26,7 +38,7 @@ module Net; module SSH; module Authentication
|
|
|
26
38
|
|
|
27
39
|
# The definition of the Windows methods and data structures used in
|
|
28
40
|
# communicating with the pageant process.
|
|
29
|
-
module Win
|
|
41
|
+
module Win # rubocop:disable Metrics/ModuleLength
|
|
30
42
|
# Compatibility on initialization
|
|
31
43
|
if RUBY_VERSION < "1.9"
|
|
32
44
|
extend DL::Importable
|
|
@@ -36,14 +48,24 @@ module Net; module SSH; module Authentication
|
|
|
36
48
|
dlload 'advapi32'
|
|
37
49
|
|
|
38
50
|
SIZEOF_DWORD = DL.sizeof('L')
|
|
39
|
-
|
|
51
|
+
elsif RUBY_VERSION < "2.1"
|
|
40
52
|
extend DL::Importer
|
|
41
53
|
dlload 'user32','kernel32', 'advapi32'
|
|
42
54
|
include DL::Win32Types
|
|
43
55
|
|
|
44
56
|
SIZEOF_DWORD = DL::SIZEOF_LONG
|
|
57
|
+
else
|
|
58
|
+
extend Fiddle::Importer
|
|
59
|
+
dlload 'user32','kernel32', 'advapi32'
|
|
60
|
+
include Fiddle::Win32Types
|
|
61
|
+
SIZEOF_DWORD = Fiddle::SIZEOF_LONG
|
|
45
62
|
end
|
|
46
63
|
|
|
64
|
+
if RUBY_ENGINE=="jruby"
|
|
65
|
+
typealias("HANDLE", "void *") # From winnt.h
|
|
66
|
+
typealias("PHANDLE", "void *") # From winnt.h
|
|
67
|
+
typealias("ULONG_PTR", "unsigned long*")
|
|
68
|
+
end
|
|
47
69
|
typealias("LPCTSTR", "char *") # From winnt.h
|
|
48
70
|
typealias("LPVOID", "void *") # From winnt.h
|
|
49
71
|
typealias("LPCVOID", "const void *") # From windef.h
|
|
@@ -62,18 +84,24 @@ module Net; module SSH; module Authentication
|
|
|
62
84
|
|
|
63
85
|
SMTO_NORMAL = 0 # From winuser.h
|
|
64
86
|
|
|
87
|
+
SUFFIX = if RUBY_ENGINE == "jruby"
|
|
88
|
+
"A"
|
|
89
|
+
else
|
|
90
|
+
""
|
|
91
|
+
end
|
|
92
|
+
|
|
65
93
|
# args: lpClassName, lpWindowName
|
|
66
|
-
extern
|
|
94
|
+
extern "HWND FindWindow#{SUFFIX}(LPCTSTR, LPCTSTR)"
|
|
67
95
|
|
|
68
96
|
# args: none
|
|
69
97
|
extern 'DWORD GetCurrentThreadId()'
|
|
70
98
|
|
|
71
99
|
# args: hFile, (ignored), flProtect, dwMaximumSizeHigh,
|
|
72
100
|
# dwMaximumSizeLow, lpName
|
|
73
|
-
extern
|
|
74
|
-
'DWORD, DWORD, LPCTSTR)
|
|
101
|
+
extern "HANDLE CreateFileMapping#{SUFFIX}(HANDLE, void *, DWORD, ' +
|
|
102
|
+
'DWORD, DWORD, LPCTSTR)"
|
|
75
103
|
|
|
76
|
-
# args: hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh,
|
|
104
|
+
# args: hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh,
|
|
77
105
|
# dwfileOffsetLow, dwNumberOfBytesToMap
|
|
78
106
|
extern 'LPVOID MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, DWORD)'
|
|
79
107
|
|
|
@@ -84,9 +112,9 @@ module Net; module SSH; module Authentication
|
|
|
84
112
|
extern 'BOOL CloseHandle(HANDLE)'
|
|
85
113
|
|
|
86
114
|
# args: hWnd, Msg, wParam, lParam, fuFlags, uTimeout, lpdwResult
|
|
87
|
-
extern
|
|
88
|
-
'UINT, UINT, PDWORD_PTR)
|
|
89
|
-
|
|
115
|
+
extern "LRESULT SendMessageTimeout#{SUFFIX}(HWND, UINT, WPARAM, LPARAM, ' +
|
|
116
|
+
'UINT, UINT, PDWORD_PTR)"
|
|
117
|
+
|
|
90
118
|
# args: none
|
|
91
119
|
extern 'DWORD GetLastError()'
|
|
92
120
|
|
|
@@ -112,8 +140,8 @@ module Net; module SSH; module Authentication
|
|
|
112
140
|
extern 'BOOL IsValidSecurityDescriptor(LPVOID)'
|
|
113
141
|
|
|
114
142
|
# Constants needed for security attribute retrieval.
|
|
115
|
-
# Specifies the access mask corresponding to the desired access
|
|
116
|
-
# rights.
|
|
143
|
+
# Specifies the access mask corresponding to the desired access
|
|
144
|
+
# rights.
|
|
117
145
|
TOKEN_QUERY = 0x8
|
|
118
146
|
|
|
119
147
|
# The value of TOKEN_USER from the TOKEN_INFORMATION_CLASS enum.
|
|
@@ -138,6 +166,13 @@ module Net; module SSH; module Authentication
|
|
|
138
166
|
'LPVOID Group', 'LPVOID Sacl',
|
|
139
167
|
'LPVOID Dacl']
|
|
140
168
|
|
|
169
|
+
# The COPYDATASTRUCT is used to send WM_COPYDATA messages
|
|
170
|
+
COPYDATASTRUCT = if RUBY_ENGINE == "jruby"
|
|
171
|
+
struct ['ULONG_PTR dwData', 'DWORD cbData', 'LPVOID lpData']
|
|
172
|
+
else
|
|
173
|
+
struct ['uintptr_t dwData', 'DWORD cbData', 'LPVOID lpData']
|
|
174
|
+
end
|
|
175
|
+
|
|
141
176
|
# Compatibility for security attribute retrieval.
|
|
142
177
|
if RUBY_VERSION < "1.9"
|
|
143
178
|
# Alias functions to > 1.9 capitalization
|
|
@@ -171,6 +206,30 @@ module Net; module SSH; module Authentication
|
|
|
171
206
|
def self.set_ptr_data(ptr, data)
|
|
172
207
|
ptr[0] = data
|
|
173
208
|
end
|
|
209
|
+
elsif RUBY_ENGINE == "jruby"
|
|
210
|
+
%w(FindWindow CreateFileMapping SendMessageTimeout).each do |name|
|
|
211
|
+
alias_method name, name+"A"
|
|
212
|
+
module_function name
|
|
213
|
+
end
|
|
214
|
+
# :nodoc:
|
|
215
|
+
module LibC
|
|
216
|
+
extend FFI::Library
|
|
217
|
+
ffi_lib FFI::Library::LIBC
|
|
218
|
+
attach_function :malloc, [:size_t], :pointer
|
|
219
|
+
attach_function :free, [:pointer], :void
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def self.malloc_ptr(size)
|
|
223
|
+
Fiddle::Pointer.new(LibC.malloc(size), size, LibC.method(:free))
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def self.get_ptr(ptr)
|
|
227
|
+
return data.address
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def self.set_ptr_data(ptr, data)
|
|
231
|
+
ptr.write_string_length(data, data.size)
|
|
232
|
+
end
|
|
174
233
|
else
|
|
175
234
|
def self.malloc_ptr(size)
|
|
176
235
|
return DL::CPtr.malloc(size, DL::RUBY_FREE)
|
|
@@ -191,22 +250,83 @@ module Net; module SSH; module Authentication
|
|
|
191
250
|
psd_information = malloc_ptr(Win::SECURITY_DESCRIPTOR.size)
|
|
192
251
|
raise_error_if_zero(
|
|
193
252
|
Win.InitializeSecurityDescriptor(psd_information,
|
|
194
|
-
Win::REVISION)
|
|
253
|
+
Win::REVISION)
|
|
254
|
+
)
|
|
195
255
|
raise_error_if_zero(
|
|
196
|
-
Win.SetSecurityDescriptorOwner(psd_information, user
|
|
197
|
-
0)
|
|
256
|
+
Win.SetSecurityDescriptorOwner(psd_information, get_sid_ptr(user),
|
|
257
|
+
0)
|
|
258
|
+
)
|
|
198
259
|
raise_error_if_zero(
|
|
199
|
-
Win.IsValidSecurityDescriptor(psd_information)
|
|
260
|
+
Win.IsValidSecurityDescriptor(psd_information)
|
|
261
|
+
)
|
|
200
262
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
sa =
|
|
205
|
-
bInheritHandle].pack("LLC")
|
|
263
|
+
sa = Win::SECURITY_ATTRIBUTES.new(to_struct_ptr(malloc_ptr(Win::SECURITY_ATTRIBUTES.size)))
|
|
264
|
+
sa.nLength = Win::SECURITY_ATTRIBUTES.size
|
|
265
|
+
sa.lpSecurityDescriptor = psd_information.to_i
|
|
266
|
+
sa.bInheritHandle = 1
|
|
206
267
|
|
|
207
268
|
return sa
|
|
208
269
|
end
|
|
209
270
|
|
|
271
|
+
if RUBY_ENGINE == "jruby"
|
|
272
|
+
def self.ptr_to_s(ptr, size)
|
|
273
|
+
ret = ptr.to_s(size)
|
|
274
|
+
ret << "\x00" while ret.size < size
|
|
275
|
+
ret
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def self.ptr_to_handle(phandle)
|
|
279
|
+
phandle.ptr
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def self.ptr_to_dword(ptr)
|
|
283
|
+
first = ptr.ptr.to_i
|
|
284
|
+
second = ptr_to_s(ptr,Win::SIZEOF_DWORD).unpack('L')[0]
|
|
285
|
+
raise "Error" unless first == second
|
|
286
|
+
first
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def self.to_token_user(ptoken_information)
|
|
290
|
+
TOKEN_USER.new(ptoken_information.to_ptr)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def self.to_struct_ptr(ptr)
|
|
294
|
+
ptr.to_ptr
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def self.get_sid(user)
|
|
298
|
+
ptr_to_s(user.to_ptr.ptr,Win::SIZEOF_DWORD).unpack('L')[0]
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def self.get_sid_ptr(user)
|
|
302
|
+
user.to_ptr.ptr
|
|
303
|
+
end
|
|
304
|
+
else
|
|
305
|
+
def self.get_sid(user)
|
|
306
|
+
user.SID
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def self.ptr_to_handle(phandle)
|
|
310
|
+
phandle.ptr.to_i
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
def self.to_struct_ptr(ptr)
|
|
314
|
+
ptr
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
def self.ptr_to_dword(ptr)
|
|
318
|
+
ptr.to_s(Win::SIZEOF_DWORD).unpack('L')[0]
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
def self.to_token_user(ptoken_information)
|
|
322
|
+
TOKEN_USER.new(ptoken_information)
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def self.get_sid_ptr(user)
|
|
326
|
+
user.SID
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
|
|
210
330
|
def self.get_current_user
|
|
211
331
|
token_handle = open_process_token(Win.GetCurrentProcess,
|
|
212
332
|
Win::TOKEN_QUERY)
|
|
@@ -220,9 +340,9 @@ module Net; module SSH; module Authentication
|
|
|
220
340
|
|
|
221
341
|
raise_error_if_zero(
|
|
222
342
|
Win.OpenProcessToken(process_handle, desired_access,
|
|
223
|
-
ptoken_handle)
|
|
224
|
-
|
|
225
|
-
|
|
343
|
+
ptoken_handle)
|
|
344
|
+
)
|
|
345
|
+
token_handle = ptr_to_handle(ptoken_handle)
|
|
226
346
|
return token_handle
|
|
227
347
|
end
|
|
228
348
|
|
|
@@ -237,7 +357,7 @@ module Net; module SSH; module Authentication
|
|
|
237
357
|
Win.GetTokenInformation(token_handle,
|
|
238
358
|
token_information_class,
|
|
239
359
|
Win::NULL, 0, preturn_length)
|
|
240
|
-
ptoken_information = malloc_ptr(preturn_length
|
|
360
|
+
ptoken_information = malloc_ptr(ptr_to_dword(preturn_length))
|
|
241
361
|
|
|
242
362
|
# This call is going to write the requested information to
|
|
243
363
|
# the memory location referenced by token_information.
|
|
@@ -246,9 +366,10 @@ module Net; module SSH; module Authentication
|
|
|
246
366
|
token_information_class,
|
|
247
367
|
ptoken_information,
|
|
248
368
|
ptoken_information.size,
|
|
249
|
-
preturn_length)
|
|
369
|
+
preturn_length)
|
|
370
|
+
)
|
|
250
371
|
|
|
251
|
-
return
|
|
372
|
+
return to_token_user(ptoken_information)
|
|
252
373
|
end
|
|
253
374
|
|
|
254
375
|
def self.raise_error_if_zero(result)
|
|
@@ -271,19 +392,17 @@ module Net; module SSH; module Authentication
|
|
|
271
392
|
|
|
272
393
|
private_class_method :new
|
|
273
394
|
|
|
274
|
-
# The factory method for creating a new Socket instance.
|
|
275
|
-
|
|
276
|
-
# the general Socket interface.
|
|
277
|
-
def self.open(location=nil)
|
|
395
|
+
# The factory method for creating a new Socket instance.
|
|
396
|
+
def self.open
|
|
278
397
|
new
|
|
279
398
|
end
|
|
280
399
|
|
|
281
|
-
# Create a new instance that communicates with the running pageant
|
|
400
|
+
# Create a new instance that communicates with the running pageant
|
|
282
401
|
# instance. If no such instance is running, this will cause an error.
|
|
283
402
|
def initialize
|
|
284
403
|
@win = Win.FindWindow("Pageant", "Pageant")
|
|
285
404
|
|
|
286
|
-
if @win == 0
|
|
405
|
+
if @win.to_i == 0
|
|
287
406
|
raise Net::SSH::Exception,
|
|
288
407
|
"pageant process not running"
|
|
289
408
|
end
|
|
@@ -296,28 +415,27 @@ module Net; module SSH; module Authentication
|
|
|
296
415
|
# the first.
|
|
297
416
|
def send(data, *args)
|
|
298
417
|
@input_buffer.append(data)
|
|
299
|
-
|
|
418
|
+
|
|
300
419
|
ret = data.length
|
|
301
|
-
|
|
420
|
+
|
|
302
421
|
while true
|
|
303
422
|
return ret if @input_buffer.length < 4
|
|
304
423
|
msg_length = @input_buffer.read_long + 4
|
|
305
424
|
@input_buffer.reset!
|
|
306
|
-
|
|
425
|
+
|
|
307
426
|
return ret if @input_buffer.length < msg_length
|
|
308
427
|
msg = @input_buffer.read!(msg_length)
|
|
309
428
|
@output_buffer.append(send_query(msg))
|
|
310
429
|
end
|
|
311
430
|
end
|
|
312
|
-
|
|
431
|
+
|
|
313
432
|
# Reads +n+ bytes from the cached result of the last query. If +n+
|
|
314
433
|
# is +nil+, returns all remaining data from the last query.
|
|
315
434
|
def read(n = nil)
|
|
316
435
|
@output_buffer.read(n)
|
|
317
436
|
end
|
|
318
437
|
|
|
319
|
-
def close
|
|
320
|
-
end
|
|
438
|
+
def close; end
|
|
321
439
|
|
|
322
440
|
# Packages the given query string and sends it to the pageant
|
|
323
441
|
# process via the Windows messaging subsystem. The result is
|
|
@@ -341,7 +459,7 @@ module Net; module SSH; module Authentication
|
|
|
341
459
|
"Creation of file mapping failed with error: #{Win.GetLastError}"
|
|
342
460
|
end
|
|
343
461
|
|
|
344
|
-
ptr = Win.MapViewOfFile(filemap, Win::FILE_MAP_WRITE, 0, 0,
|
|
462
|
+
ptr = Win.MapViewOfFile(filemap, Win::FILE_MAP_WRITE, 0, 0,
|
|
345
463
|
0)
|
|
346
464
|
|
|
347
465
|
if ptr.nil? || ptr.null?
|
|
@@ -350,10 +468,13 @@ module Net; module SSH; module Authentication
|
|
|
350
468
|
|
|
351
469
|
Win.set_ptr_data(ptr, query)
|
|
352
470
|
|
|
353
|
-
|
|
354
|
-
|
|
471
|
+
# using struct to achieve proper alignment and field size on 64-bit platform
|
|
472
|
+
cds = Win::COPYDATASTRUCT.new(Win.malloc_ptr(Win::COPYDATASTRUCT.size))
|
|
473
|
+
cds.dwData = AGENT_COPYDATA_ID
|
|
474
|
+
cds.cbData = mapname.size + 1
|
|
475
|
+
cds.lpData = Win.get_cstr(mapname)
|
|
355
476
|
succ = Win.SendMessageTimeout(@win, Win::WM_COPYDATA, Win::NULL,
|
|
356
|
-
cds, Win::SMTO_NORMAL, 5000, id)
|
|
477
|
+
cds.to_ptr, Win::SMTO_NORMAL, 5000, id)
|
|
357
478
|
|
|
358
479
|
if succ > 0
|
|
359
480
|
retlen = 4 + ptr.to_s(4).unpack("N")[0]
|
|
@@ -69,8 +69,9 @@ module Net; module SSH; module Authentication
|
|
|
69
69
|
attempted << name
|
|
70
70
|
|
|
71
71
|
debug { "trying #{name}" }
|
|
72
|
-
begin
|
|
73
|
-
|
|
72
|
+
begin
|
|
73
|
+
auth_class = Methods.const_get(name.split(/\W+/).map { |p| p.capitalize }.join)
|
|
74
|
+
method = auth_class.new(self, key_manager: key_manager, password_prompt: options[:password_prompt])
|
|
74
75
|
rescue NameError
|
|
75
76
|
debug{"Mechanism #{name} was requested, but isn't a known type. Ignoring it."}
|
|
76
77
|
next
|
data/lib/net/ssh/buffer.rb
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
require 'net/ssh/ruby_compat'
|
|
2
2
|
require 'net/ssh/transport/openssl'
|
|
3
3
|
|
|
4
|
+
require 'net/ssh/authentication/ed25519_loader'
|
|
5
|
+
|
|
4
6
|
module Net; module SSH
|
|
5
7
|
|
|
6
8
|
# Net::SSH::Buffer is a flexible class for building and parsing binary
|
|
@@ -34,6 +36,7 @@ module Net; module SSH
|
|
|
34
36
|
# * :long => write a 4-byte integer (#write_long)
|
|
35
37
|
# * :byte => write a single byte (#write_byte)
|
|
36
38
|
# * :string => write a 4-byte length followed by character data (#write_string)
|
|
39
|
+
# * :mstring => same as string, but caller cannot resuse the string, avoids potential duplication (#write_moved)
|
|
37
40
|
# * :bool => write a single byte, interpreted as a boolean (#write_bool)
|
|
38
41
|
# * :bignum => write an SSH-encoded bignum (#write_bignum)
|
|
39
42
|
# * :key => write an SSH-encoded key value (#write_key)
|
|
@@ -159,7 +162,7 @@ module Net; module SSH
|
|
|
159
162
|
index = @content.index(pattern, @position) or return nil
|
|
160
163
|
length = case pattern
|
|
161
164
|
when String then pattern.length
|
|
162
|
-
when
|
|
165
|
+
when Integer then 1
|
|
163
166
|
when Regexp then $&.length
|
|
164
167
|
end
|
|
165
168
|
index && read(index+length)
|
|
@@ -182,7 +185,7 @@ module Net; module SSH
|
|
|
182
185
|
consume!
|
|
183
186
|
data
|
|
184
187
|
end
|
|
185
|
-
|
|
188
|
+
|
|
186
189
|
# Return the next 8 bytes as a 64-bit integer (in network byte order).
|
|
187
190
|
# Returns nil if there are less than 8 bytes remaining to be read in the
|
|
188
191
|
# buffer.
|
|
@@ -245,16 +248,32 @@ module Net; module SSH
|
|
|
245
248
|
case type
|
|
246
249
|
when /^ssh-dss(-cert-v01@openssh\.com)?$/
|
|
247
250
|
key = OpenSSL::PKey::DSA.new
|
|
248
|
-
key.
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
251
|
+
if key.respond_to?(:set_pqg)
|
|
252
|
+
key.set_pqg(read_bignum, read_bignum, read_bignum)
|
|
253
|
+
else
|
|
254
|
+
key.p = read_bignum
|
|
255
|
+
key.q = read_bignum
|
|
256
|
+
key.g = read_bignum
|
|
257
|
+
end
|
|
258
|
+
if key.respond_to?(:set_key)
|
|
259
|
+
key.set_key(read_bignum, nil)
|
|
260
|
+
else
|
|
261
|
+
key.pub_key = read_bignum
|
|
262
|
+
end
|
|
252
263
|
|
|
253
264
|
when /^ssh-rsa(-cert-v01@openssh\.com)?$/
|
|
254
265
|
key = OpenSSL::PKey::RSA.new
|
|
255
|
-
key.
|
|
256
|
-
|
|
257
|
-
|
|
266
|
+
if key.respond_to?(:set_key)
|
|
267
|
+
e = read_bignum
|
|
268
|
+
n = read_bignum
|
|
269
|
+
key.set_key(n, e, nil)
|
|
270
|
+
else
|
|
271
|
+
key.e = read_bignum
|
|
272
|
+
key.n = read_bignum
|
|
273
|
+
end
|
|
274
|
+
when /^ssh-ed25519$/
|
|
275
|
+
Net::SSH::Authentication::ED25519Loader.raiseUnlessLoaded("unsupported key type `#{type}'")
|
|
276
|
+
key = Net::SSH::Authentication::ED25519::PubKey.read_keyblob(self)
|
|
258
277
|
when /^ecdsa\-sha2\-(\w*)$/
|
|
259
278
|
unless defined?(OpenSSL::PKey::EC)
|
|
260
279
|
raise NotImplementedError, "unsupported key type `#{type}'"
|
|
@@ -281,7 +300,14 @@ module Net; module SSH
|
|
|
281
300
|
# Writes the given data literally into the string. Does not alter the
|
|
282
301
|
# read position. Returns the buffer object.
|
|
283
302
|
def write(*data)
|
|
284
|
-
data.each { |datum| @content << datum }
|
|
303
|
+
data.each { |datum| @content << datum.dup.force_encoding('BINARY') }
|
|
304
|
+
self
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
# Optimized version of write where the caller gives up ownership of string
|
|
308
|
+
# to the method. This way we can mutate the string.
|
|
309
|
+
def write_moved(string)
|
|
310
|
+
@content << string.force_encoding('BINARY')
|
|
285
311
|
self
|
|
286
312
|
end
|
|
287
313
|
|
|
@@ -324,6 +350,19 @@ module Net; module SSH
|
|
|
324
350
|
self
|
|
325
351
|
end
|
|
326
352
|
|
|
353
|
+
# Writes each argument to the buffer as an SSH2-encoded string. Each
|
|
354
|
+
# string is prefixed by its length, encoded as a 4-byte long integer.
|
|
355
|
+
# Does not alter the read position. Returns the buffer object.
|
|
356
|
+
# Might alter arguments see write_moved
|
|
357
|
+
def write_mstring(*text)
|
|
358
|
+
text.each do |string|
|
|
359
|
+
s = string.to_s
|
|
360
|
+
write_long(s.bytesize)
|
|
361
|
+
write_moved(s)
|
|
362
|
+
end
|
|
363
|
+
self
|
|
364
|
+
end
|
|
365
|
+
|
|
327
366
|
# Writes each argument to the buffer as a (C-style) boolean, with 1
|
|
328
367
|
# meaning true, and 0 meaning false. Does not alter the read position.
|
|
329
368
|
# Returns the buffer object.
|
data/lib/net/ssh/buffered_io.rb
CHANGED
|
@@ -66,6 +66,9 @@ module Net; module SSH
|
|
|
66
66
|
debug { "read #{data.length} bytes" }
|
|
67
67
|
input.append(data)
|
|
68
68
|
return data.length
|
|
69
|
+
rescue EOFError => e
|
|
70
|
+
@input_errors << e
|
|
71
|
+
return 0
|
|
69
72
|
end
|
|
70
73
|
|
|
71
74
|
# Read up to +length+ bytes from the input buffer. If +length+ is nil,
|
|
@@ -143,21 +146,23 @@ module Net; module SSH
|
|
|
143
146
|
# Module#include to add this module.
|
|
144
147
|
def initialize_buffered_io
|
|
145
148
|
@input = Net::SSH::Buffer.new
|
|
149
|
+
@input_errors = []
|
|
146
150
|
@output = Net::SSH::Buffer.new
|
|
151
|
+
@output_errors = []
|
|
147
152
|
end
|
|
148
153
|
end
|
|
149
154
|
|
|
150
155
|
|
|
151
|
-
|
|
156
|
+
|
|
152
157
|
# Fixes for two issues by Miklós Fazekas:
|
|
153
158
|
#
|
|
154
|
-
# * if client closes a forwarded connection, but the server is
|
|
159
|
+
# * if client closes a forwarded connection, but the server is
|
|
155
160
|
# reading, net-ssh terminates with IOError socket closed.
|
|
156
|
-
# * if client force closes (RST) a forwarded connection, but
|
|
161
|
+
# * if client force closes (RST) a forwarded connection, but
|
|
157
162
|
# server is reading, net-ssh terminates with [an exception]
|
|
158
163
|
#
|
|
159
|
-
# See:
|
|
160
|
-
#
|
|
164
|
+
# See:
|
|
165
|
+
#
|
|
161
166
|
# http://net-ssh.lighthouseapp.com/projects/36253/tickets/7
|
|
162
167
|
# http://github.com/net-ssh/net-ssh/tree/portfwfix
|
|
163
168
|
#
|
|
@@ -168,24 +173,24 @@ module Net; module SSH
|
|
|
168
173
|
rescue Errno::ECONNRESET => e
|
|
169
174
|
debug { "connection was reset => shallowing exception:#{e}" }
|
|
170
175
|
return 0
|
|
171
|
-
rescue IOError => e
|
|
172
|
-
if e.message =~ /closed/ then
|
|
176
|
+
rescue IOError => e
|
|
177
|
+
if e.message =~ /closed/ then
|
|
173
178
|
debug { "connection was reset => shallowing exception:#{e}" }
|
|
174
179
|
return 0
|
|
175
180
|
else
|
|
176
181
|
raise
|
|
177
|
-
end
|
|
182
|
+
end
|
|
178
183
|
end
|
|
179
184
|
end
|
|
180
|
-
|
|
185
|
+
|
|
181
186
|
def send_pending
|
|
182
187
|
begin
|
|
183
|
-
super
|
|
188
|
+
super
|
|
184
189
|
rescue Errno::ECONNRESET => e
|
|
185
190
|
debug { "connection was reset => shallowing exception:#{e}" }
|
|
186
191
|
return 0
|
|
187
192
|
rescue IOError => e
|
|
188
|
-
if e.message =~ /closed/ then
|
|
193
|
+
if e.message =~ /closed/ then
|
|
189
194
|
debug { "connection was reset => shallowing exception:#{e}" }
|
|
190
195
|
return 0
|
|
191
196
|
else
|
|
@@ -194,5 +199,5 @@ module Net; module SSH
|
|
|
194
199
|
end
|
|
195
200
|
end
|
|
196
201
|
end
|
|
197
|
-
|
|
202
|
+
|
|
198
203
|
end; end
|
data/lib/net/ssh/config.rb
CHANGED
|
@@ -59,7 +59,7 @@ module Net; module SSH
|
|
|
59
59
|
# given +files+ (defaulting to the list of files returned by
|
|
60
60
|
# #default_files), translates the resulting hash into the options
|
|
61
61
|
# recognized by Net::SSH, and returns them.
|
|
62
|
-
def for(host, files=
|
|
62
|
+
def for(host, files=expandable_default_files)
|
|
63
63
|
translate(files.inject({}) { |settings, file|
|
|
64
64
|
load(file, host, settings)
|
|
65
65
|
})
|
|
@@ -144,7 +144,7 @@ module Net; module SSH
|
|
|
144
144
|
def translate(settings)
|
|
145
145
|
auth_methods = default_auth_methods.clone
|
|
146
146
|
(auth_methods << 'challenge-response').uniq!
|
|
147
|
-
ret = settings.inject({:auth_methods
|
|
147
|
+
ret = settings.inject({auth_methods: auth_methods}) do |hash, (key, value)|
|
|
148
148
|
case key
|
|
149
149
|
when 'bindaddress' then
|
|
150
150
|
hash[:bind_address] = value
|
|
@@ -178,6 +178,15 @@ module Net; module SSH
|
|
|
178
178
|
hash[:keys] = value
|
|
179
179
|
when 'macs' then
|
|
180
180
|
hash[:hmac] = value.split(/,/)
|
|
181
|
+
when 'serveralivecountmax'
|
|
182
|
+
hash[:keepalive_maxcount] = value.to_i if value
|
|
183
|
+
when 'serveraliveinterval'
|
|
184
|
+
if value && value.to_i > 0
|
|
185
|
+
hash[:keepalive] = true
|
|
186
|
+
hash[:keepalive_interval] = value.to_i
|
|
187
|
+
else
|
|
188
|
+
hash[:keepalive] = false
|
|
189
|
+
end
|
|
181
190
|
when 'passwordauthentication'
|
|
182
191
|
if value
|
|
183
192
|
(hash[:auth_methods] << 'password').uniq!
|
|
@@ -230,14 +239,36 @@ module Net; module SSH
|
|
|
230
239
|
|
|
231
240
|
private
|
|
232
241
|
|
|
242
|
+
def expandable_default_files
|
|
243
|
+
default_files.keep_if do |path|
|
|
244
|
+
begin
|
|
245
|
+
File.expand_path(path)
|
|
246
|
+
true
|
|
247
|
+
rescue ArgumentError
|
|
248
|
+
false
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
233
253
|
# Converts an ssh_config pattern into a regex for matching against
|
|
234
254
|
# host names.
|
|
235
255
|
def pattern2regex(pattern)
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
256
|
+
tail = pattern
|
|
257
|
+
prefix = ""
|
|
258
|
+
while !tail.empty? do
|
|
259
|
+
head,sep,tail = tail.partition(/[\*\?]/)
|
|
260
|
+
prefix = prefix + Regexp.quote(head)
|
|
261
|
+
case sep
|
|
262
|
+
when '*'
|
|
263
|
+
prefix += '.*'
|
|
264
|
+
when '?'
|
|
265
|
+
prefix += '.'
|
|
266
|
+
when ''
|
|
267
|
+
else
|
|
268
|
+
fail "Unpexpcted sep:#{sep}"
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
Regexp.new("^" + prefix + "$", true)
|
|
241
272
|
end
|
|
242
273
|
|
|
243
274
|
# Converts the given size into an integer number of bytes.
|
|
@@ -249,7 +280,7 @@ module Net; module SSH
|
|
|
249
280
|
else size.to_i
|
|
250
281
|
end
|
|
251
282
|
end
|
|
252
|
-
|
|
283
|
+
|
|
253
284
|
def merge_challenge_response_with_keyboard_interactive(hash)
|
|
254
285
|
if hash[:auth_methods].include?('challenge-response')
|
|
255
286
|
hash[:auth_methods].delete('challenge-response')
|