net-ssh 1.1.4 → 2.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.
- data/CHANGELOG.rdoc +37 -0
- data/Manifest +101 -0
- data/README.rdoc +110 -0
- data/Rakefile +26 -0
- data/{THANKS → THANKS.rdoc} +2 -5
- data/lib/net/ssh.rb +189 -57
- data/lib/net/ssh/authentication/agent.rb +175 -0
- data/lib/net/ssh/authentication/constants.rb +18 -0
- data/lib/net/ssh/authentication/key_manager.rb +166 -0
- data/lib/net/ssh/authentication/methods/abstract.rb +60 -0
- data/lib/net/ssh/authentication/methods/hostbased.rb +71 -0
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +66 -0
- data/lib/net/ssh/authentication/methods/password.rb +39 -0
- data/lib/net/ssh/authentication/methods/publickey.rb +92 -0
- data/lib/net/ssh/authentication/pageant.rb +176 -0
- data/lib/net/ssh/authentication/session.rb +116 -0
- data/lib/net/ssh/buffer.rb +339 -0
- data/lib/net/ssh/buffered_io.rb +149 -0
- data/lib/net/ssh/config.rb +173 -0
- data/lib/net/ssh/connection/channel.rb +575 -454
- data/lib/net/ssh/connection/constants.rb +31 -45
- data/lib/net/ssh/connection/session.rb +569 -0
- data/lib/net/ssh/connection/term.rb +176 -88
- data/lib/net/ssh/errors.rb +83 -61
- data/lib/net/ssh/key_factory.rb +85 -0
- data/lib/net/ssh/known_hosts.rb +129 -0
- data/lib/net/ssh/loggable.rb +61 -0
- data/lib/net/ssh/packet.rb +102 -0
- data/lib/net/ssh/prompt.rb +93 -0
- data/lib/net/ssh/proxy/errors.rb +8 -28
- data/lib/net/ssh/proxy/http.rb +75 -107
- data/lib/net/ssh/proxy/socks4.rb +35 -48
- data/lib/net/ssh/proxy/socks5.rb +76 -108
- data/lib/net/ssh/service/forward.rb +267 -0
- data/lib/net/ssh/test.rb +89 -0
- data/lib/net/ssh/test/channel.rb +129 -0
- data/lib/net/ssh/test/extensions.rb +152 -0
- data/lib/net/ssh/test/kex.rb +44 -0
- data/lib/net/ssh/test/local_packet.rb +51 -0
- data/lib/net/ssh/test/packet.rb +81 -0
- data/lib/net/ssh/test/remote_packet.rb +38 -0
- data/lib/net/ssh/test/script.rb +157 -0
- data/lib/net/ssh/test/socket.rb +59 -0
- data/lib/net/ssh/transport/algorithms.rb +384 -0
- data/lib/net/ssh/transport/cipher_factory.rb +72 -0
- data/lib/net/ssh/transport/constants.rb +22 -58
- data/lib/net/ssh/transport/hmac.rb +31 -0
- data/lib/net/ssh/transport/hmac/abstract.rb +48 -0
- data/lib/net/ssh/transport/hmac/md5.rb +12 -0
- data/lib/net/ssh/transport/hmac/md5_96.rb +11 -0
- data/lib/net/ssh/transport/hmac/none.rb +15 -0
- data/lib/net/ssh/transport/hmac/sha1.rb +13 -0
- data/lib/net/ssh/transport/hmac/sha1_96.rb +11 -0
- data/lib/net/ssh/transport/identity_cipher.rb +40 -0
- data/lib/net/ssh/transport/kex.rb +13 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +208 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +77 -0
- data/lib/net/ssh/{util → transport}/openssl.rb +22 -40
- data/lib/net/ssh/transport/packet_stream.rb +230 -0
- data/lib/net/ssh/transport/server_version.rb +61 -0
- data/lib/net/ssh/transport/session.rb +225 -303
- data/lib/net/ssh/transport/state.rb +170 -0
- data/lib/net/ssh/verifiers/lenient.rb +30 -0
- data/lib/net/ssh/verifiers/null.rb +12 -0
- data/lib/net/ssh/verifiers/strict.rb +53 -0
- data/lib/net/ssh/version.rb +57 -26
- data/net-ssh.gemspec +54 -0
- data/setup.rb +1585 -0
- data/test/authentication/methods/common.rb +28 -0
- data/test/authentication/methods/test_abstract.rb +51 -0
- data/test/authentication/methods/test_hostbased.rb +108 -0
- data/test/authentication/methods/test_keyboard_interactive.rb +98 -0
- data/test/authentication/methods/test_password.rb +50 -0
- data/test/authentication/methods/test_publickey.rb +123 -0
- data/test/authentication/test_agent.rb +205 -0
- data/test/authentication/test_key_manager.rb +100 -0
- data/test/authentication/test_session.rb +93 -0
- data/test/common.rb +106 -0
- data/test/configs/exact_match +8 -0
- data/test/configs/wild_cards +14 -0
- data/test/connection/test_channel.rb +452 -0
- data/test/connection/test_session.rb +483 -0
- data/test/test_all.rb +6 -0
- data/test/test_buffer.rb +336 -0
- data/test/test_buffered_io.rb +63 -0
- data/test/test_config.rb +78 -0
- data/test/test_key_factory.rb +67 -0
- data/test/transport/hmac/test_md5.rb +34 -0
- data/test/transport/hmac/test_md5_96.rb +25 -0
- data/test/transport/hmac/test_none.rb +34 -0
- data/test/transport/hmac/test_sha1.rb +34 -0
- data/test/transport/hmac/test_sha1_96.rb +25 -0
- data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +146 -0
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +92 -0
- data/test/transport/test_algorithms.rb +302 -0
- data/test/transport/test_cipher_factory.rb +163 -0
- data/test/transport/test_hmac.rb +34 -0
- data/test/transport/test_identity_cipher.rb +40 -0
- data/test/transport/test_packet_stream.rb +433 -0
- data/test/transport/test_server_version.rb +55 -0
- data/test/transport/test_session.rb +312 -0
- data/test/transport/test_state.rb +173 -0
- metadata +102 -253
- data/ChangeLog +0 -560
- data/LICENSE +0 -7
- data/NEWS +0 -152
- data/README +0 -14
- data/bin/rb-keygen +0 -210
- data/doc/LICENSE-BSD +0 -27
- data/doc/LICENSE-GPL +0 -280
- data/doc/LICENSE-RUBY +0 -56
- data/doc/manual-html/chapter-1.html +0 -388
- data/doc/manual-html/chapter-2.html +0 -552
- data/doc/manual-html/chapter-3.html +0 -470
- data/doc/manual-html/chapter-4.html +0 -413
- data/doc/manual-html/chapter-5.html +0 -525
- data/doc/manual-html/chapter-6.html +0 -456
- data/doc/manual-html/chapter-7.html +0 -343
- data/doc/manual-html/index.html +0 -235
- data/doc/manual-html/stylesheets/manual.css +0 -270
- data/doc/manual-html/stylesheets/ruby.css +0 -17
- data/doc/manual/chapter.erb +0 -38
- data/doc/manual/example.erb +0 -18
- data/doc/manual/index.erb +0 -29
- data/doc/manual/manual.rb +0 -311
- data/doc/manual/manual.yml +0 -73
- data/doc/manual/page.erb +0 -87
- data/doc/manual/parts/0000.txt +0 -5
- data/doc/manual/parts/0001.txt +0 -3
- data/doc/manual/parts/0002.txt +0 -40
- data/doc/manual/parts/0003.txt +0 -6
- data/doc/manual/parts/0004.txt +0 -7
- data/doc/manual/parts/0005.txt +0 -1
- data/doc/manual/parts/0006.txt +0 -49
- data/doc/manual/parts/0007.txt +0 -67
- data/doc/manual/parts/0008.txt +0 -43
- data/doc/manual/parts/0009.txt +0 -14
- data/doc/manual/parts/0010.txt +0 -7
- data/doc/manual/parts/0011.txt +0 -14
- data/doc/manual/parts/0012.txt +0 -3
- data/doc/manual/parts/0013.txt +0 -20
- data/doc/manual/parts/0014.txt +0 -32
- data/doc/manual/parts/0015.txt +0 -14
- data/doc/manual/parts/0016.txt +0 -28
- data/doc/manual/parts/0017.txt +0 -50
- data/doc/manual/parts/0018.txt +0 -35
- data/doc/manual/parts/0019.txt +0 -7
- data/doc/manual/parts/0020.txt +0 -72
- data/doc/manual/parts/0021.txt +0 -50
- data/doc/manual/parts/0022.txt +0 -42
- data/doc/manual/parts/0023.txt +0 -51
- data/doc/manual/parts/0024.txt +0 -18
- data/doc/manual/parts/0025.txt +0 -18
- data/doc/manual/parts/0026.txt +0 -15
- data/doc/manual/parts/0027.txt +0 -37
- data/doc/manual/parts/0028.txt +0 -16
- data/doc/manual/parts/0029.txt +0 -1
- data/doc/manual/parts/0030.txt +0 -52
- data/doc/manual/parts/0031.txt +0 -25
- data/doc/manual/stylesheets/manual.css +0 -270
- data/doc/manual/stylesheets/ruby.css +0 -17
- data/doc/manual/tutorial.erb +0 -30
- data/examples/auth-forward.rb +0 -41
- data/examples/channel-demo.rb +0 -81
- data/examples/port-forward.rb +0 -51
- data/examples/process-demo.rb +0 -91
- data/examples/remote-net-port-forward.rb +0 -45
- data/examples/remote-port-forward.rb +0 -80
- data/examples/shell-demo.rb +0 -46
- data/examples/ssh-client.rb +0 -67
- data/examples/sync-shell-demo.rb +0 -69
- data/examples/tail-demo.rb +0 -49
- data/lib/net/ssh/connection/driver.rb +0 -446
- data/lib/net/ssh/connection/services.rb +0 -72
- data/lib/net/ssh/host-key-verifier.rb +0 -52
- data/lib/net/ssh/known-hosts.rb +0 -96
- data/lib/net/ssh/lenient-host-key-verifier.rb +0 -25
- data/lib/net/ssh/null-host-key-verifier.rb +0 -14
- data/lib/net/ssh/service/agentforward/driver.rb +0 -78
- data/lib/net/ssh/service/agentforward/services.rb +0 -41
- data/lib/net/ssh/service/forward/driver.rb +0 -319
- data/lib/net/ssh/service/forward/local-network-handler.rb +0 -71
- data/lib/net/ssh/service/forward/remote-network-handler.rb +0 -83
- data/lib/net/ssh/service/forward/services.rb +0 -76
- data/lib/net/ssh/service/process/driver.rb +0 -153
- data/lib/net/ssh/service/process/open.rb +0 -193
- data/lib/net/ssh/service/process/popen3.rb +0 -178
- data/lib/net/ssh/service/process/services.rb +0 -66
- data/lib/net/ssh/service/services.rb +0 -60
- data/lib/net/ssh/service/shell/driver.rb +0 -86
- data/lib/net/ssh/service/shell/services.rb +0 -54
- data/lib/net/ssh/service/shell/shell.rb +0 -222
- data/lib/net/ssh/service/shell/sync.rb +0 -114
- data/lib/net/ssh/session.rb +0 -305
- data/lib/net/ssh/transport/algorithm-negotiator.rb +0 -275
- data/lib/net/ssh/transport/compress/compressor.rb +0 -53
- data/lib/net/ssh/transport/compress/decompressor.rb +0 -53
- data/lib/net/ssh/transport/compress/none-compressor.rb +0 -39
- data/lib/net/ssh/transport/compress/none-decompressor.rb +0 -39
- data/lib/net/ssh/transport/compress/services.rb +0 -68
- data/lib/net/ssh/transport/compress/zlib-compressor.rb +0 -60
- data/lib/net/ssh/transport/compress/zlib-decompressor.rb +0 -52
- data/lib/net/ssh/transport/errors.rb +0 -47
- data/lib/net/ssh/transport/identity-cipher.rb +0 -61
- data/lib/net/ssh/transport/kex/dh-gex.rb +0 -106
- data/lib/net/ssh/transport/kex/dh.rb +0 -249
- data/lib/net/ssh/transport/kex/services.rb +0 -62
- data/lib/net/ssh/transport/ossl/buffer-factory.rb +0 -52
- data/lib/net/ssh/transport/ossl/buffer.rb +0 -87
- data/lib/net/ssh/transport/ossl/cipher-factory.rb +0 -98
- data/lib/net/ssh/transport/ossl/digest-factory.rb +0 -51
- data/lib/net/ssh/transport/ossl/hmac-factory.rb +0 -71
- data/lib/net/ssh/transport/ossl/hmac/hmac.rb +0 -62
- data/lib/net/ssh/transport/ossl/hmac/md5-96.rb +0 -44
- data/lib/net/ssh/transport/ossl/hmac/md5.rb +0 -46
- data/lib/net/ssh/transport/ossl/hmac/none.rb +0 -46
- data/lib/net/ssh/transport/ossl/hmac/services.rb +0 -68
- data/lib/net/ssh/transport/ossl/hmac/sha1-96.rb +0 -44
- data/lib/net/ssh/transport/ossl/hmac/sha1.rb +0 -45
- data/lib/net/ssh/transport/ossl/key-factory.rb +0 -116
- data/lib/net/ssh/transport/ossl/services.rb +0 -149
- data/lib/net/ssh/transport/packet-stream.rb +0 -236
- data/lib/net/ssh/transport/services.rb +0 -146
- data/lib/net/ssh/transport/version-negotiator.rb +0 -73
- data/lib/net/ssh/userauth/agent.rb +0 -222
- data/lib/net/ssh/userauth/constants.rb +0 -35
- data/lib/net/ssh/userauth/driver.rb +0 -183
- data/lib/net/ssh/userauth/methods/hostbased.rb +0 -119
- data/lib/net/ssh/userauth/methods/keyboard-interactive.rb +0 -104
- data/lib/net/ssh/userauth/methods/password.rb +0 -70
- data/lib/net/ssh/userauth/methods/publickey.rb +0 -137
- data/lib/net/ssh/userauth/methods/services.rb +0 -90
- data/lib/net/ssh/userauth/pageant.rb +0 -197
- data/lib/net/ssh/userauth/services.rb +0 -141
- data/lib/net/ssh/userauth/userkeys.rb +0 -258
- data/lib/net/ssh/util/buffer.rb +0 -274
- data/lib/net/ssh/util/prompter.rb +0 -73
- data/test/ALL-TESTS.rb +0 -18
- data/test/connection/tc_channel.rb +0 -136
- data/test/connection/tc_driver.rb +0 -287
- data/test/connection/tc_integration.rb +0 -87
- data/test/proxy/tc_http.rb +0 -209
- data/test/proxy/tc_socks4.rb +0 -148
- data/test/proxy/tc_socks5.rb +0 -214
- data/test/service/agentforward/tc_driver.rb +0 -138
- data/test/service/forward/tc_driver.rb +0 -289
- data/test/service/forward/tc_local_network_handler.rb +0 -123
- data/test/service/forward/tc_remote_network_handler.rb +0 -111
- data/test/service/process/tc_driver.rb +0 -79
- data/test/service/process/tc_integration.rb +0 -119
- data/test/service/process/tc_open.rb +0 -179
- data/test/service/process/tc_popen3.rb +0 -164
- data/test/tc_integration.rb +0 -80
- data/test/transport/compress/tc_none_compress.rb +0 -41
- data/test/transport/compress/tc_none_decompress.rb +0 -45
- data/test/transport/compress/tc_zlib_compress.rb +0 -61
- data/test/transport/compress/tc_zlib_decompress.rb +0 -48
- data/test/transport/kex/tc_dh.rb +0 -312
- data/test/transport/kex/tc_dh_gex.rb +0 -71
- data/test/transport/ossl/fixtures/dsa-encrypted +0 -15
- data/test/transport/ossl/fixtures/dsa-encrypted-bad +0 -15
- data/test/transport/ossl/fixtures/dsa-unencrypted +0 -12
- data/test/transport/ossl/fixtures/dsa-unencrypted-bad +0 -12
- data/test/transport/ossl/fixtures/dsa-unencrypted.pub +0 -1
- data/test/transport/ossl/fixtures/not-a-private-key +0 -4
- data/test/transport/ossl/fixtures/not-supported +0 -2
- data/test/transport/ossl/fixtures/rsa-encrypted +0 -18
- data/test/transport/ossl/fixtures/rsa-encrypted-bad +0 -18
- data/test/transport/ossl/fixtures/rsa-unencrypted +0 -15
- data/test/transport/ossl/fixtures/rsa-unencrypted-bad +0 -15
- data/test/transport/ossl/fixtures/rsa-unencrypted.pub +0 -1
- data/test/transport/ossl/hmac/tc_hmac.rb +0 -58
- data/test/transport/ossl/hmac/tc_md5.rb +0 -50
- data/test/transport/ossl/hmac/tc_md5_96.rb +0 -50
- data/test/transport/ossl/hmac/tc_none.rb +0 -50
- data/test/transport/ossl/hmac/tc_sha1.rb +0 -50
- data/test/transport/ossl/hmac/tc_sha1_96.rb +0 -50
- data/test/transport/ossl/tc_buffer.rb +0 -97
- data/test/transport/ossl/tc_buffer_factory.rb +0 -67
- data/test/transport/ossl/tc_cipher_factory.rb +0 -84
- data/test/transport/ossl/tc_digest_factory.rb +0 -39
- data/test/transport/ossl/tc_hmac_factory.rb +0 -72
- data/test/transport/ossl/tc_key_factory.rb +0 -199
- data/test/transport/tc_algorithm_negotiator.rb +0 -170
- data/test/transport/tc_identity_cipher.rb +0 -52
- data/test/transport/tc_integration.rb +0 -115
- data/test/transport/tc_packet_stream.rb +0 -184
- data/test/transport/tc_session.rb +0 -296
- data/test/transport/tc_version_negotiator.rb +0 -86
- data/test/userauth/methods/tc_hostbased.rb +0 -136
- data/test/userauth/methods/tc_password.rb +0 -89
- data/test/userauth/methods/tc_publickey.rb +0 -167
- data/test/userauth/tc_agent.rb +0 -223
- data/test/userauth/tc_driver.rb +0 -190
- data/test/userauth/tc_integration.rb +0 -97
- data/test/userauth/tc_userkeys.rb +0 -265
- data/test/util/tc_buffer.rb +0 -217
@@ -1,340 +1,262 @@
|
|
1
|
-
#--
|
2
|
-
# =============================================================================
|
3
|
-
# Copyright (c) 2004,2005 Jamis Buck (jamis@37signals.com)
|
4
|
-
# All rights reserved.
|
5
|
-
#
|
6
|
-
# This source file is distributed as part of the Net::SSH Secure Shell Client
|
7
|
-
# library for Ruby. This file (and the library as a whole) may be used only as
|
8
|
-
# allowed by either the BSD license, or the Ruby license (or, by association
|
9
|
-
# with the Ruby license, the GPL). See the "doc" subdirectory of the Net::SSH
|
10
|
-
# distribution for the texts of these licenses.
|
11
|
-
# -----------------------------------------------------------------------------
|
12
|
-
# net-ssh website : http://net-ssh.rubyforge.org
|
13
|
-
# project website: http://rubyforge.org/projects/net-ssh
|
14
|
-
# =============================================================================
|
15
|
-
#++
|
16
|
-
|
17
1
|
require 'socket'
|
18
2
|
require 'timeout'
|
19
|
-
|
20
|
-
require 'net/ssh/
|
3
|
+
|
4
|
+
require 'net/ssh/errors'
|
5
|
+
require 'net/ssh/loggable'
|
21
6
|
require 'net/ssh/version'
|
7
|
+
require 'net/ssh/transport/algorithms'
|
8
|
+
require 'net/ssh/transport/constants'
|
9
|
+
require 'net/ssh/transport/packet_stream'
|
10
|
+
require 'net/ssh/transport/server_version'
|
11
|
+
require 'net/ssh/verifiers/null'
|
12
|
+
require 'net/ssh/verifiers/strict'
|
13
|
+
require 'net/ssh/verifiers/lenient'
|
22
14
|
|
23
|
-
module Net
|
24
|
-
module SSH
|
25
|
-
module Transport
|
26
|
-
|
27
|
-
# Represents a low-level SSH session, at the transport protocol level.
|
28
|
-
# This handles the algorithm negotiation and key exchange for any SSH
|
29
|
-
# connection.
|
30
|
-
class Session
|
31
|
-
include Constants
|
32
|
-
|
33
|
-
# the unique session identifier
|
34
|
-
attr_reader :session_id
|
35
|
-
|
36
|
-
# the collection of algorithms currently being used
|
37
|
-
attr_reader :algorithms
|
38
|
-
|
39
|
-
# the hostname that was requested
|
40
|
-
attr_reader :host
|
41
|
-
|
42
|
-
# the port that was requested
|
43
|
-
attr_reader :port
|
44
|
-
|
45
|
-
attr_writer :logger
|
46
|
-
attr_writer :default_port
|
47
|
-
attr_writer :version_negotiator
|
48
|
-
attr_writer :algorithm_negotiator
|
49
|
-
attr_writer :socket_factory
|
50
|
-
attr_writer :packet_sender
|
51
|
-
attr_writer :packet_receiver
|
52
|
-
attr_writer :ciphers
|
53
|
-
attr_writer :hmacs
|
54
|
-
attr_writer :kexs
|
55
|
-
attr_writer :compressors
|
56
|
-
attr_writer :decompressors
|
57
|
-
|
58
|
-
# The name that Net::SSH reports for itself
|
59
|
-
NAME = "Ruby/Net::SSH"
|
60
|
-
|
61
|
-
# The SSH protocol supported by Net::SSH.
|
62
|
-
PROTOCOL = "SSH-2.0"
|
63
|
-
|
64
|
-
# Returns the version string of this client.
|
65
|
-
def self.version
|
66
|
-
"#{PROTOCOL}-#{NAME}_#{Net::SSH::Version::STRING}"
|
67
|
-
end
|
15
|
+
module Net; module SSH; module Transport
|
68
16
|
|
69
|
-
|
70
|
-
|
71
|
-
|
17
|
+
# The transport layer represents the lowest level of the SSH protocol, and
|
18
|
+
# implements basic message exchanging and protocol initialization. It will
|
19
|
+
# never be instantiated directly (unless you really know what you're about),
|
20
|
+
# but will instead be created for you automatically when you create a new
|
21
|
+
# SSH session via Net::SSH.start.
|
22
|
+
class Session
|
23
|
+
include Constants, Loggable
|
72
24
|
|
73
|
-
|
74
|
-
|
75
|
-
# uninitialized +self+ will be passed to the block, so that dependencies
|
76
|
-
# may be injected.
|
77
|
-
def initialize( host, options={} )
|
78
|
-
@saved_message = nil
|
79
|
-
@session_id = nil
|
80
|
-
@host = host
|
25
|
+
# The standard port for the SSH protocol.
|
26
|
+
DEFAULT_PORT = 22
|
81
27
|
|
82
|
-
|
28
|
+
# The host to connect to, as given to the constructor.
|
29
|
+
attr_reader :host
|
83
30
|
|
84
|
-
|
31
|
+
# The port number to connect to, as given in the options to the constructor.
|
32
|
+
# If no port number was given, this will default to DEFAULT_PORT.
|
33
|
+
attr_reader :port
|
85
34
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
end
|
35
|
+
# The underlying socket object being used to communicate with the remote
|
36
|
+
# host.
|
37
|
+
attr_reader :socket
|
90
38
|
|
91
|
-
|
39
|
+
# The ServerVersion instance that encapsulates the negotiated protocol
|
40
|
+
# version.
|
41
|
+
attr_reader :server_version
|
92
42
|
|
93
|
-
|
94
|
-
|
95
|
-
( options[:proxy] || @socket_factory ).open( host, @port )
|
96
|
-
end
|
43
|
+
# The Algorithms instance used to perform key exchanges.
|
44
|
+
attr_reader :algorithms
|
97
45
|
|
98
|
-
|
99
|
-
|
46
|
+
# The host-key verifier object used to verify host keys, to ensure that
|
47
|
+
# the connection is not being spoofed.
|
48
|
+
attr_reader :host_key_verifier
|
100
49
|
|
101
|
-
|
102
|
-
|
103
|
-
:server_version_string =>
|
104
|
-
@version_negotiator.negotiate( @socket, self.class.version ) }
|
50
|
+
# The hash of options that were given to the object at initialization.
|
51
|
+
attr_reader :options
|
105
52
|
|
106
|
-
|
107
|
-
|
108
|
-
|
53
|
+
# Instantiates a new transport layer abstraction. This will block until
|
54
|
+
# the initial key exchange completes, leaving you with a ready-to-use
|
55
|
+
# transport session.
|
56
|
+
def initialize(host, options={})
|
57
|
+
self.logger = options[:logger]
|
109
58
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
addr = @socket.getpeername
|
114
|
-
ip_address = Socket.getnameinfo(addr, Socket::NI_NUMERICHOST | Socket::NI_NUMERICSERV).first
|
115
|
-
{ :ip => ip_address, :port => @port.to_i, :host => @host }
|
116
|
-
end
|
117
|
-
end
|
59
|
+
@host = host
|
60
|
+
@port = options[:port] || DEFAULT_PORT
|
61
|
+
@options = options
|
118
62
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
begin
|
125
|
-
@hostname =
|
126
|
-
Socket.getnameinfo( sockaddr, Socket::NI_NAMEREQD ).first
|
127
|
-
rescue
|
128
|
-
begin
|
129
|
-
@hostname = Socket.getnameinfo( sockaddr ).first
|
130
|
-
rescue
|
131
|
-
begin
|
132
|
-
@hostname = Socket.gethostbyname( Socket.gethostname ).first
|
133
|
-
rescue
|
134
|
-
@logger.error "the client ipaddr/name could not be determined"
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
63
|
+
debug { "establishing connection to #{@host}:#{@port}" }
|
64
|
+
factory = options[:proxy] || TCPSocket
|
65
|
+
@socket = timeout(options[:timeout] || 0) { factory.open(@host, @port) }
|
66
|
+
@socket.extend(PacketStream)
|
67
|
+
@socket.logger = @logger
|
138
68
|
|
139
|
-
|
140
|
-
end
|
69
|
+
debug { "connection established" }
|
141
70
|
|
142
|
-
|
143
|
-
@doing_kexinit = true
|
144
|
-
@algorithms = @algorithm_negotiator.negotiate( self, @options )
|
71
|
+
@queue = []
|
145
72
|
|
146
|
-
|
147
|
-
@kex_info[ :client_algorithm_packet ] = @algorithms.client_packet
|
73
|
+
@host_key_verifier = select_host_key_verifier(options[:paranoid])
|
148
74
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
75
|
+
@server_version = ServerVersion.new(socket, logger)
|
76
|
+
|
77
|
+
@algorithms = Algorithms.new(self, options)
|
78
|
+
wait { algorithms.initialized? }
|
79
|
+
end
|
153
80
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
81
|
+
# Returns the host (and possibly IP address) in a format compatible with
|
82
|
+
# SSH known-host files.
|
83
|
+
def host_as_string
|
84
|
+
@host_as_string ||= begin
|
85
|
+
string = "#{host}"
|
86
|
+
string = "[#{string}]:#{port}" if port != DEFAULT_PORT
|
87
|
+
if socket.peer_ip != host
|
88
|
+
string2 = socket.peer_ip
|
89
|
+
string2 = "[#{string2}]:#{port}" if port != DEFAULT_PORT
|
90
|
+
string << "," << string2
|
158
91
|
end
|
92
|
+
string
|
93
|
+
end
|
94
|
+
end
|
159
95
|
|
160
|
-
|
161
|
-
|
96
|
+
# Cleans up (see PacketStream#cleanup) and closes the underlying socket.
|
97
|
+
def close
|
98
|
+
socket.cleanup
|
99
|
+
socket.close
|
100
|
+
end
|
162
101
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
need = block_size if need < block_size
|
169
|
-
end
|
102
|
+
# Returns a new service_request packet for the given service name, ready
|
103
|
+
# for sending to the server.
|
104
|
+
def service_request(service)
|
105
|
+
Net::SSH::Buffer.from(:byte, SERVICE_REQUEST, :string, service)
|
106
|
+
end
|
170
107
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
108
|
+
# Requests a rekey operation, and blocks until the operation completes.
|
109
|
+
# If a rekey is already pending, this returns immediately, having no
|
110
|
+
# effect.
|
111
|
+
def rekey!
|
112
|
+
if !algorithms.pending?
|
113
|
+
algorithms.rekey!
|
114
|
+
wait { algorithms.initialized? }
|
115
|
+
end
|
116
|
+
end
|
175
117
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
# (possibly) compressed.
|
184
|
-
def exchange_keys
|
185
|
-
@kex_info[ :need_bytes ] = get_kex_byte_requirement
|
186
|
-
|
187
|
-
kex = @kexs.fetch( @algorithms.kex )
|
188
|
-
result = kex.exchange_keys( self, @kex_info )
|
189
|
-
|
190
|
-
@shared_secret = result[ :shared_secret ]
|
191
|
-
hash = result[ :session_id ]
|
192
|
-
@session_id = hash unless @session_id
|
193
|
-
@server_key = result[ :server_key ]
|
194
|
-
@hashing_algorithm = result[ :hashing_algorithm ]
|
195
|
-
|
196
|
-
# prepare the ciphers, et. al.
|
197
|
-
secret_bin = @shared_secret.to_ssh
|
198
|
-
|
199
|
-
iv_c2s = @hashing_algorithm.digest( secret_bin +
|
200
|
-
hash +
|
201
|
-
"A" +
|
202
|
-
@session_id )
|
203
|
-
iv_s2c = @hashing_algorithm.digest( secret_bin +
|
204
|
-
hash +
|
205
|
-
"B" +
|
206
|
-
@session_id )
|
207
|
-
key_c2s = @hashing_algorithm.digest( secret_bin +
|
208
|
-
hash +
|
209
|
-
"C" +
|
210
|
-
@session_id )
|
211
|
-
key_s2c = @hashing_algorithm.digest( secret_bin +
|
212
|
-
hash +
|
213
|
-
"D" +
|
214
|
-
@session_id )
|
215
|
-
mac_key_c2s = @hashing_algorithm.digest( secret_bin +
|
216
|
-
hash +
|
217
|
-
"E" +
|
218
|
-
@session_id )
|
219
|
-
mac_key_s2c = @hashing_algorithm.digest( secret_bin +
|
220
|
-
hash +
|
221
|
-
"F" +
|
222
|
-
@session_id )
|
223
|
-
|
224
|
-
cipher_c2s = @ciphers.get(
|
225
|
-
@algorithms.encryption_c2s, iv_c2s, key_c2s,
|
226
|
-
secret_bin, hash, @hashing_algorithm,
|
227
|
-
true )
|
228
|
-
|
229
|
-
cipher_s2c = @ciphers.get(
|
230
|
-
@algorithms.encryption_s2c, iv_s2c, key_s2c,
|
231
|
-
secret_bin, hash, @hashing_algorithm,
|
232
|
-
false )
|
233
|
-
|
234
|
-
mac_c2s = @hmacs.get( @algorithms.mac_c2s, mac_key_c2s );
|
235
|
-
mac_s2c = @hmacs.get( @algorithms.mac_s2c, mac_key_s2c );
|
236
|
-
|
237
|
-
compression_c2s = @compressors[ @algorithms.compression_c2s ].new(
|
238
|
-
:level => @algorithms.compression_level )
|
239
|
-
compression_s2c = @decompressors[ @algorithms.compression_s2c ].new
|
240
|
-
|
241
|
-
@packet_sender.set_algorithms cipher_c2s, mac_c2s, compression_c2s
|
242
|
-
@packet_receiver.set_algorithms cipher_s2c, mac_s2c, compression_s2c
|
243
|
-
end
|
244
|
-
private :exchange_keys
|
245
|
-
|
246
|
-
# Waits for the next message from the server, handling common requests
|
247
|
-
# like DISCONNECT, IGNORE, DEBUG, and KEXINIT in the background. The
|
248
|
-
# next message is returned as a [ type, buffer ] tuple, where the buffer
|
249
|
-
# is a Net::SSH::Util::ReaderBuffer.
|
250
|
-
def wait_for_message
|
251
|
-
buffer = type = nil
|
252
|
-
|
253
|
-
if @saved_message
|
254
|
-
type, buffer = @saved_message
|
255
|
-
@logger.debug "returning saved message: #{type}" if @logger.debug?
|
256
|
-
@saved_message = nil
|
257
|
-
else
|
258
|
-
loop do
|
259
|
-
if @logger.debug?
|
260
|
-
@logger.debug "waiting for packet from server..."
|
261
|
-
end
|
262
|
-
|
263
|
-
buffer = @packet_receiver.get
|
264
|
-
next unless buffer
|
265
|
-
|
266
|
-
type = buffer.read_byte
|
267
|
-
@logger.debug "got packet of type #{type}" if @logger.debug?
|
268
|
-
|
269
|
-
case type
|
270
|
-
when DISCONNECT
|
271
|
-
reason_code = buffer.read_long
|
272
|
-
description = buffer.read_string
|
273
|
-
language = buffer.read_string
|
274
|
-
raise Net::SSH::Transport::Disconnect,
|
275
|
-
"disconnected: #{description} (#{reason_code})"
|
276
|
-
|
277
|
-
when IGNORE
|
278
|
-
# do nothing
|
279
|
-
@logger.info "received IGNORE message " +
|
280
|
-
"(#{buffer.read_string.inspect})" if @logger.debug?
|
281
|
-
|
282
|
-
when DEBUG
|
283
|
-
# do nothing
|
284
|
-
@logger.info "received DEBUG message" if @logger.debug?
|
285
|
-
always_display = buffer.read_bool
|
286
|
-
message = buffer.read_string
|
287
|
-
language = buffer.read_string
|
288
|
-
if always_display
|
289
|
-
@logger.warn "#{message} (#{language})" if @logger.warn?
|
290
|
-
else
|
291
|
-
@logger.debug "#{message} (#{language})" if @logger.debug?
|
292
|
-
end
|
293
|
-
|
294
|
-
when KEXINIT
|
295
|
-
# unless we're already doing a key-exchange, do key
|
296
|
-
# re-exchange
|
297
|
-
if !@doing_kexinit
|
298
|
-
@logger.info "re-key requested" if @logger.info?
|
299
|
-
@saved_message = [ type, buffer ]
|
300
|
-
kexinit
|
301
|
-
else
|
302
|
-
break
|
303
|
-
end
|
304
|
-
|
305
|
-
else
|
306
|
-
break
|
307
|
-
end
|
308
|
-
end
|
309
|
-
end
|
118
|
+
# Returns immediately if a rekey is already in process. Otherwise, if a
|
119
|
+
# rekey is needed (as indicated by the socket, see PacketStream#if_needs_rekey?)
|
120
|
+
# one is performed, causing this method to block until it completes.
|
121
|
+
def rekey_as_needed
|
122
|
+
return if algorithms.pending?
|
123
|
+
socket.if_needs_rekey? { rekey! }
|
124
|
+
end
|
310
125
|
|
311
|
-
|
312
|
-
|
126
|
+
# Returns a hash of information about the peer (remote) side of the socket,
|
127
|
+
# including :ip, :port, :host, and :canonized (see #host_as_string).
|
128
|
+
def peer
|
129
|
+
@peer ||= { :ip => socket.peer_ip, :port => @port.to_i, :host => @host, :canonized => host_as_string }
|
130
|
+
end
|
313
131
|
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
end
|
132
|
+
# Blocks until a new packet is available to be read, and returns that
|
133
|
+
# packet. See #poll_message.
|
134
|
+
def next_message
|
135
|
+
poll_message(:block)
|
136
|
+
end
|
320
137
|
|
321
|
-
|
138
|
+
# Tries to read the next packet from the socket. If mode is :nonblock (the
|
139
|
+
# default), this will not block and will return nil if there are no packets
|
140
|
+
# waiting to be read. Otherwise, this will block until a packet is
|
141
|
+
# available. Note that some packet types (DISCONNECT, IGNORE, UNIMPLEMENTED,
|
142
|
+
# DEBUG, and KEXINIT) are handled silently by this method, and will never
|
143
|
+
# be returned.
|
144
|
+
#
|
145
|
+
# If a key-exchange is in process and a disallowed packet type is
|
146
|
+
# received, it will be enqueued and otherwise ignored. When a key-exchange
|
147
|
+
# is not in process, and consume_queue is true, packets will be first
|
148
|
+
# read from the queue before the socket is queried.
|
149
|
+
def poll_message(mode=:nonblock, consume_queue=true)
|
150
|
+
loop do
|
151
|
+
if consume_queue && @queue.any? && algorithms.allow?(@queue.first)
|
152
|
+
return @queue.shift
|
322
153
|
end
|
323
154
|
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
155
|
+
packet = socket.next_packet(mode)
|
156
|
+
return nil if packet.nil?
|
157
|
+
|
158
|
+
case packet.type
|
159
|
+
when DISCONNECT
|
160
|
+
raise Net::SSH::Disconnect, "disconnected: #{packet[:description]} (#{packet[:reason_code]})"
|
161
|
+
|
162
|
+
when IGNORE
|
163
|
+
debug { "IGNORE packet recieved: #{packet[:data].inspect}" }
|
164
|
+
|
165
|
+
when UNIMPLEMENTED
|
166
|
+
lwarn { "UNIMPLEMENTED: #{packet[:number]}" }
|
330
167
|
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
168
|
+
when DEBUG
|
169
|
+
send(packet[:always_display] ? :fatal : :debug) { packet[:message] }
|
170
|
+
|
171
|
+
when KEXINIT
|
172
|
+
algorithms.accept_kexinit(packet)
|
173
|
+
|
174
|
+
else
|
175
|
+
return packet if algorithms.allow?(packet)
|
176
|
+
push(packet)
|
335
177
|
end
|
336
178
|
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Waits (blocks) until the given block returns true. If no block is given,
|
182
|
+
# this just waits long enough to see if there are any pending packets. Any
|
183
|
+
# packets read are enqueued (see #push).
|
184
|
+
def wait
|
185
|
+
loop do
|
186
|
+
break if block_given? && yield
|
187
|
+
message = poll_message(:nonblock, false)
|
188
|
+
push(message) if message
|
189
|
+
break if !block_given?
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Adds the given packet to the packet queue. If the queue is non-empty,
|
194
|
+
# #poll_message will return packets from the queue in the order they
|
195
|
+
# were received.
|
196
|
+
def push(packet)
|
197
|
+
@queue.push(packet)
|
198
|
+
end
|
199
|
+
|
200
|
+
# Sends the given message via the packet stream, blocking until the
|
201
|
+
# entire message has been sent.
|
202
|
+
def send_message(message)
|
203
|
+
socket.send_packet(message)
|
204
|
+
end
|
205
|
+
|
206
|
+
# Enqueues the given message, such that it will be sent at the earliest
|
207
|
+
# opportunity. This does not block, but returns immediately.
|
208
|
+
def enqueue_message(message)
|
209
|
+
socket.enqueue_packet(message)
|
210
|
+
end
|
211
|
+
|
212
|
+
# Configure's the packet stream's client state with the given set of
|
213
|
+
# options. This is typically used to define the cipher, compression, and
|
214
|
+
# hmac algorithms to use when sending packets to the server.
|
215
|
+
def configure_client(options={})
|
216
|
+
socket.client.set(options)
|
217
|
+
end
|
337
218
|
|
219
|
+
# Configure's the packet stream's server state with the given set of
|
220
|
+
# options. This is typically used to define the cipher, compression, and
|
221
|
+
# hmac algorithms to use when reading packets from the server.
|
222
|
+
def configure_server(options={})
|
223
|
+
socket.server.set(options)
|
338
224
|
end
|
225
|
+
|
226
|
+
# Sets a new hint for the packet stream, which the packet stream may use
|
227
|
+
# to change its behavior. (See PacketStream#hints).
|
228
|
+
def hint(which, value=true)
|
229
|
+
socket.hints[which] = value
|
230
|
+
end
|
231
|
+
|
232
|
+
public
|
233
|
+
|
234
|
+
# this method is primarily for use in tests
|
235
|
+
attr_reader :queue #:nodoc:
|
236
|
+
|
237
|
+
private
|
238
|
+
|
239
|
+
# Instantiates a new host-key verification class, based on the value of
|
240
|
+
# the parameter. When true or nil, the default Lenient verifier is
|
241
|
+
# returned. If it is false, the Null verifier is returned, and if it is
|
242
|
+
# :very, the Strict verifier is returned. If the argument happens to
|
243
|
+
# respond to :verify, it is returned directly. Otherwise, an exception
|
244
|
+
# is raised.
|
245
|
+
def select_host_key_verifier(paranoid)
|
246
|
+
case paranoid
|
247
|
+
when true, nil then
|
248
|
+
Net::SSH::Verifiers::Lenient.new
|
249
|
+
when false then
|
250
|
+
Net::SSH::Verifiers::Null.new
|
251
|
+
when :very then
|
252
|
+
Net::SSH::Verifiers::Strict.new
|
253
|
+
else
|
254
|
+
if paranoid.respond_to?(:verify)
|
255
|
+
paranoid
|
256
|
+
else
|
257
|
+
raise ArgumentError, "argument to :paranoid is not valid: #{paranoid.inspect}"
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
339
261
|
end
|
340
|
-
end
|
262
|
+
end; end; end
|