net-ssh 5.0.0.beta1 → 5.0.0.beta2

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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.rubocop_todo.yml +98 -258
  5. data/CHANGES.txt +8 -0
  6. data/Gemfile +1 -3
  7. data/Rakefile +37 -39
  8. data/lib/net/ssh.rb +26 -25
  9. data/lib/net/ssh/authentication/agent.rb +228 -225
  10. data/lib/net/ssh/authentication/certificate.rb +166 -164
  11. data/lib/net/ssh/authentication/constants.rb +17 -14
  12. data/lib/net/ssh/authentication/ed25519.rb +107 -104
  13. data/lib/net/ssh/authentication/ed25519_loader.rb +32 -28
  14. data/lib/net/ssh/authentication/key_manager.rb +5 -3
  15. data/lib/net/ssh/authentication/methods/abstract.rb +53 -47
  16. data/lib/net/ssh/authentication/methods/hostbased.rb +32 -33
  17. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +2 -4
  18. data/lib/net/ssh/authentication/methods/none.rb +10 -10
  19. data/lib/net/ssh/authentication/methods/password.rb +13 -13
  20. data/lib/net/ssh/authentication/methods/publickey.rb +54 -55
  21. data/lib/net/ssh/authentication/pageant.rb +468 -465
  22. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +44 -0
  23. data/lib/net/ssh/authentication/session.rb +127 -123
  24. data/lib/net/ssh/buffer.rb +305 -303
  25. data/lib/net/ssh/buffered_io.rb +163 -162
  26. data/lib/net/ssh/config.rb +230 -227
  27. data/lib/net/ssh/connection/channel.rb +659 -654
  28. data/lib/net/ssh/connection/constants.rb +30 -26
  29. data/lib/net/ssh/connection/event_loop.rb +108 -104
  30. data/lib/net/ssh/connection/keepalive.rb +54 -50
  31. data/lib/net/ssh/connection/session.rb +677 -678
  32. data/lib/net/ssh/connection/term.rb +180 -176
  33. data/lib/net/ssh/errors.rb +101 -99
  34. data/lib/net/ssh/key_factory.rb +108 -108
  35. data/lib/net/ssh/known_hosts.rb +148 -154
  36. data/lib/net/ssh/loggable.rb +56 -54
  37. data/lib/net/ssh/packet.rb +82 -78
  38. data/lib/net/ssh/prompt.rb +55 -53
  39. data/lib/net/ssh/proxy/command.rb +103 -102
  40. data/lib/net/ssh/proxy/errors.rb +12 -8
  41. data/lib/net/ssh/proxy/http.rb +92 -91
  42. data/lib/net/ssh/proxy/https.rb +42 -39
  43. data/lib/net/ssh/proxy/jump.rb +50 -47
  44. data/lib/net/ssh/proxy/socks4.rb +0 -2
  45. data/lib/net/ssh/proxy/socks5.rb +11 -11
  46. data/lib/net/ssh/ruby_compat.rb +1 -0
  47. data/lib/net/ssh/service/forward.rb +364 -362
  48. data/lib/net/ssh/test.rb +85 -83
  49. data/lib/net/ssh/test/channel.rb +146 -142
  50. data/lib/net/ssh/test/extensions.rb +148 -146
  51. data/lib/net/ssh/test/kex.rb +35 -31
  52. data/lib/net/ssh/test/local_packet.rb +48 -44
  53. data/lib/net/ssh/test/packet.rb +87 -84
  54. data/lib/net/ssh/test/remote_packet.rb +35 -31
  55. data/lib/net/ssh/test/script.rb +173 -171
  56. data/lib/net/ssh/test/socket.rb +59 -55
  57. data/lib/net/ssh/transport/algorithms.rb +413 -412
  58. data/lib/net/ssh/transport/cipher_factory.rb +108 -105
  59. data/lib/net/ssh/transport/constants.rb +35 -31
  60. data/lib/net/ssh/transport/ctr.rb +1 -1
  61. data/lib/net/ssh/transport/hmac.rb +1 -1
  62. data/lib/net/ssh/transport/hmac/abstract.rb +67 -64
  63. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +1 -1
  64. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +1 -1
  65. data/lib/net/ssh/transport/identity_cipher.rb +55 -51
  66. data/lib/net/ssh/transport/kex.rb +2 -4
  67. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +47 -40
  68. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +201 -197
  69. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -56
  70. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +94 -87
  71. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +17 -10
  72. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +17 -10
  73. data/lib/net/ssh/transport/key_expander.rb +29 -25
  74. data/lib/net/ssh/transport/openssl.rb +17 -30
  75. data/lib/net/ssh/transport/packet_stream.rb +193 -192
  76. data/lib/net/ssh/transport/server_version.rb +64 -66
  77. data/lib/net/ssh/transport/session.rb +286 -284
  78. data/lib/net/ssh/transport/state.rb +198 -196
  79. data/lib/net/ssh/verifiers/lenient.rb +29 -25
  80. data/lib/net/ssh/verifiers/null.rb +13 -9
  81. data/lib/net/ssh/verifiers/secure.rb +45 -45
  82. data/lib/net/ssh/verifiers/strict.rb +20 -16
  83. data/lib/net/ssh/version.rb +55 -53
  84. data/net-ssh.gemspec +4 -4
  85. data/support/ssh_tunnel_bug.rb +2 -2
  86. metadata +25 -24
  87. metadata.gz.sig +0 -0
@@ -0,0 +1,44 @@
1
+
2
+ require 'openssl'
3
+
4
+ module Net
5
+ module SSH
6
+ module Authentication
7
+ # Public key fingerprinting utility module - internal not part of API.
8
+ # This is included in pubkey classes and called from there. All RSA, DSA, and ECC keys
9
+ # are supported.
10
+ #
11
+ # require 'net/ssh'
12
+ # my_pubkey_text = File.read('/path/to/id_ed25519.pub')
13
+ # #=> "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDB2NBh4GJPPUN1kXPMu8b633Xcv55WoKC3OkBjFAbzJ alice@example.com"
14
+ # my_pubkey = Net::SSH::KeyFactory.load_data_public_key(my_pubkey_text)
15
+ # #=> #<Net::SSH::Authentication::ED25519::PubKey:0x00007fc8e91819b0
16
+ # my_pubkey.fingerprint
17
+ # #=> "2f:7f:97:21:76:a4:0f:38:c4:fe:d8:b4:6a:39:72:30"
18
+ # my_pubkey.fingerprint('SHA256')
19
+ # #=> "SHA256:u6mXnY8P1b0FODGp8mckqOB33u8+jvkSCtJbD5Q9klg"
20
+ module PubKeyFingerprint # :nodoc:
21
+ # Return the key's fingerprint. Algorithm may be either +MD5+ (default),
22
+ # or +SHA256+. For +SHA256+, fingerprints are in the same format
23
+ # returned by OpenSSH's <tt>`ssh-add -l -E SHA256`</tt>, i.e.,
24
+ # trailing base64 padding '=' characters are stripped and the
25
+ # literal string +SHA256:+ is prepended.
26
+ def fingerprint(algorithm='MD5')
27
+ @fingerprint ||= {}
28
+ @fingerprint[algorithm] ||= PubKeyFingerprint.fingerprint(to_blob, algorithm)
29
+ end
30
+
31
+ def self.fingerprint(blob, algorithm='MD5')
32
+ case algorithm.to_s.upcase
33
+ when 'MD5'
34
+ OpenSSL::Digest.hexdigest(algorithm, blob).scan(/../).join(":")
35
+ when 'SHA256'
36
+ "SHA256:#{Base64.encode64(OpenSSL::Digest.digest(algorithm, blob)).chomp.gsub(/=+\z/, '')}"
37
+ else
38
+ raise OpenSSL::Digest::DigestError, "unsupported ssh key digest #{algorithm}"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -8,149 +8,153 @@ require 'net/ssh/authentication/methods/hostbased'
8
8
  require 'net/ssh/authentication/methods/password'
9
9
  require 'net/ssh/authentication/methods/keyboard_interactive'
10
10
 
11
- module Net; module SSH; module Authentication
11
+ module Net
12
+ module SSH
13
+ module Authentication
12
14
 
13
- # Raised if the current authentication method is not allowed
14
- class DisallowedMethod < Net::SSH::Exception
15
- end
15
+ # Raised if the current authentication method is not allowed
16
+ class DisallowedMethod < Net::SSH::Exception
17
+ end
16
18
 
17
- # Represents an authentication session. It manages the authentication of
18
- # a user over an established connection (the "transport" object, see
19
- # Net::SSH::Transport::Session).
20
- #
21
- # The use of an authentication session to manage user authentication is
22
- # internal to Net::SSH (specifically Net::SSH.start). Consumers of the
23
- # Net::SSH library will never need to access this class directly.
24
- class Session
25
- include Transport::Constants, Constants, Loggable
19
+ # Represents an authentication session. It manages the authentication of
20
+ # a user over an established connection (the "transport" object, see
21
+ # Net::SSH::Transport::Session).
22
+ #
23
+ # The use of an authentication session to manage user authentication is
24
+ # internal to Net::SSH (specifically Net::SSH.start). Consumers of the
25
+ # Net::SSH library will never need to access this class directly.
26
+ class Session
27
+ include Loggable
28
+ include Constants
29
+ include Transport::Constants
26
30
 
27
- # transport layer abstraction
28
- attr_reader :transport
31
+ # transport layer abstraction
32
+ attr_reader :transport
29
33
 
30
- # the list of authentication methods to try
31
- attr_reader :auth_methods
34
+ # the list of authentication methods to try
35
+ attr_reader :auth_methods
32
36
 
33
- # the list of authentication methods that are allowed
34
- attr_reader :allowed_auth_methods
37
+ # the list of authentication methods that are allowed
38
+ attr_reader :allowed_auth_methods
35
39
 
36
- # a hash of options, given at construction time
37
- attr_reader :options
40
+ # a hash of options, given at construction time
41
+ attr_reader :options
38
42
 
39
- # Instantiates a new Authentication::Session object over the given
40
- # transport layer abstraction.
41
- def initialize(transport, options={})
42
- self.logger = transport.logger
43
- @transport = transport
43
+ # Instantiates a new Authentication::Session object over the given
44
+ # transport layer abstraction.
45
+ def initialize(transport, options={})
46
+ self.logger = transport.logger
47
+ @transport = transport
44
48
 
45
- @auth_methods = options[:auth_methods] || Net::SSH::Config.default_auth_methods
46
- @options = options
49
+ @auth_methods = options[:auth_methods] || Net::SSH::Config.default_auth_methods
50
+ @options = options
47
51
 
48
- @allowed_auth_methods = @auth_methods
49
- end
52
+ @allowed_auth_methods = @auth_methods
53
+ end
50
54
 
51
- # Attempts to authenticate the given user, in preparation for the next
52
- # service request. Returns true if an authentication method succeeds in
53
- # authenticating the user, and false otherwise.
54
- def authenticate(next_service, username, password=nil)
55
- debug { "beginning authentication of `#{username}'" }
56
-
57
- transport.send_message(transport.service_request("ssh-userauth"))
58
- expect_message(SERVICE_ACCEPT)
59
-
60
- key_manager = KeyManager.new(logger, options)
61
- keys.each { |key| key_manager.add(key) } unless keys.empty?
62
- key_data.each { |key2| key_manager.add_key_data(key2) } unless key_data.empty?
63
-
64
- attempted = []
65
-
66
- @auth_methods.each do |name|
67
- begin
68
- next unless @allowed_auth_methods.include?(name)
69
- attempted << name
70
-
71
- debug { "trying #{name}" }
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])
75
- rescue NameError
76
- debug{"Mechanism #{name} was requested, but isn't a known type. Ignoring it."}
77
- next
55
+ # Attempts to authenticate the given user, in preparation for the next
56
+ # service request. Returns true if an authentication method succeeds in
57
+ # authenticating the user, and false otherwise.
58
+ def authenticate(next_service, username, password=nil)
59
+ debug { "beginning authentication of `#{username}'" }
60
+
61
+ transport.send_message(transport.service_request("ssh-userauth"))
62
+ expect_message(SERVICE_ACCEPT)
63
+
64
+ key_manager = KeyManager.new(logger, options)
65
+ keys.each { |key| key_manager.add(key) } unless keys.empty?
66
+ key_data.each { |key2| key_manager.add_key_data(key2) } unless key_data.empty?
67
+
68
+ attempted = []
69
+
70
+ @auth_methods.each do |name|
71
+ begin
72
+ next unless @allowed_auth_methods.include?(name)
73
+ attempted << name
74
+
75
+ debug { "trying #{name}" }
76
+ begin
77
+ auth_class = Methods.const_get(name.split(/\W+/).map { |p| p.capitalize }.join)
78
+ method = auth_class.new(self, key_manager: key_manager, password_prompt: options[:password_prompt])
79
+ rescue NameError
80
+ debug {"Mechanism #{name} was requested, but isn't a known type. Ignoring it."}
81
+ next
82
+ end
83
+
84
+ return true if method.authenticate(next_service, username, password)
85
+ rescue Net::SSH::Authentication::DisallowedMethod
86
+ end
78
87
  end
79
88
 
80
- return true if method.authenticate(next_service, username, password)
81
- rescue Net::SSH::Authentication::DisallowedMethod
89
+ error { "all authorization methods failed (tried #{attempted.join(', ')})" }
90
+ return false
91
+ ensure
92
+ key_manager.finish if key_manager
82
93
  end
83
- end
84
-
85
- error { "all authorization methods failed (tried #{attempted.join(', ')})" }
86
- return false
87
- ensure
88
- key_manager.finish if key_manager
89
- end
90
-
91
- # Blocks until a packet is received. It silently handles USERAUTH_BANNER
92
- # packets, and will raise an error if any packet is received that is not
93
- # valid during user authentication.
94
- def next_message
95
- loop do
96
- packet = transport.next_message
97
-
98
- case packet.type
99
- when USERAUTH_BANNER
100
- info { packet[:message] }
101
- # TODO add a hook for people to retrieve the banner when it is sent
102
-
103
- when USERAUTH_FAILURE
104
- @allowed_auth_methods = packet[:authentications].split(/,/)
105
- debug { "allowed methods: #{packet[:authentications]}" }
106
- return packet
107
-
108
- when USERAUTH_METHOD_RANGE, SERVICE_ACCEPT
109
- return packet
110
-
111
- when USERAUTH_SUCCESS
112
- transport.hint :authenticated
113
- return packet
114
94
 
115
- else
116
- raise Net::SSH::Exception, "unexpected message #{packet.type} (#{packet})"
95
+ # Blocks until a packet is received. It silently handles USERAUTH_BANNER
96
+ # packets, and will raise an error if any packet is received that is not
97
+ # valid during user authentication.
98
+ def next_message
99
+ loop do
100
+ packet = transport.next_message
101
+
102
+ case packet.type
103
+ when USERAUTH_BANNER
104
+ info { packet[:message] }
105
+ # TODO add a hook for people to retrieve the banner when it is sent
106
+
107
+ when USERAUTH_FAILURE
108
+ @allowed_auth_methods = packet[:authentications].split(/,/)
109
+ debug { "allowed methods: #{packet[:authentications]}" }
110
+ return packet
111
+
112
+ when USERAUTH_METHOD_RANGE, SERVICE_ACCEPT
113
+ return packet
114
+
115
+ when USERAUTH_SUCCESS
116
+ transport.hint :authenticated
117
+ return packet
118
+
119
+ else
120
+ raise Net::SSH::Exception, "unexpected message #{packet.type} (#{packet})"
121
+ end
122
+ end
117
123
  end
118
- end
119
- end
120
124
 
121
- # Blocks until a packet is received, and returns it if it is of the given
122
- # type. If it is not, an exception is raised.
123
- def expect_message(type)
124
- message = next_message
125
- unless message.type == type
126
- raise Net::SSH::Exception, "expected #{type}, got #{message.type} (#{message})"
127
- end
128
- message
129
- end
125
+ # Blocks until a packet is received, and returns it if it is of the given
126
+ # type. If it is not, an exception is raised.
127
+ def expect_message(type)
128
+ message = next_message
129
+ raise Net::SSH::Exception, "expected #{type}, got #{message.type} (#{message})" unless message.type == type
130
+ message
131
+ end
130
132
 
131
- private
133
+ private
132
134
 
133
- # Returns an array of paths to the key files usually defined
134
- # by system default.
135
- def default_keys
136
- if defined?(OpenSSL::PKey::EC)
137
- %w(~/.ssh/id_ed25519 ~/.ssh/id_rsa ~/.ssh/id_dsa ~/.ssh/id_ecdsa
138
- ~/.ssh2/id_ed25519 ~/.ssh2/id_rsa ~/.ssh2/id_dsa ~/.ssh2/id_ecdsa)
139
- else
140
- %w(~/.ssh/id_dsa ~/.ssh/id_rsa ~/.ssh2/id_dsa ~/.ssh2/id_rsa)
135
+ # Returns an array of paths to the key files usually defined
136
+ # by system default.
137
+ def default_keys
138
+ if defined?(OpenSSL::PKey::EC)
139
+ %w[~/.ssh/id_ed25519 ~/.ssh/id_rsa ~/.ssh/id_dsa ~/.ssh/id_ecdsa
140
+ ~/.ssh2/id_ed25519 ~/.ssh2/id_rsa ~/.ssh2/id_dsa ~/.ssh2/id_ecdsa]
141
+ else
142
+ %w[~/.ssh/id_dsa ~/.ssh/id_rsa ~/.ssh2/id_dsa ~/.ssh2/id_rsa]
143
+ end
141
144
  end
142
- end
143
145
 
144
- # Returns an array of paths to the key files that should be used when
145
- # attempting any key-based authentication mechanism.
146
- def keys
147
- Array(options[:keys] || default_keys)
148
- end
146
+ # Returns an array of paths to the key files that should be used when
147
+ # attempting any key-based authentication mechanism.
148
+ def keys
149
+ Array(options[:keys])
150
+ end
149
151
 
150
- # Returns an array of the key data that should be used when
151
- # attempting any key-based authentication mechanism.
152
- def key_data
153
- Array(options[:key_data])
152
+ # Returns an array of the key data that should be used when
153
+ # attempting any key-based authentication mechanism.
154
+ def key_data
155
+ Array(options[:key_data])
156
+ end
154
157
  end
158
+ end
155
159
  end
156
- end; end; end
160
+ end
@@ -4,254 +4,255 @@ require 'net/ssh/transport/openssl'
4
4
  require 'net/ssh/authentication/certificate'
5
5
  require 'net/ssh/authentication/ed25519_loader'
6
6
 
7
- module Net; module SSH
8
-
9
- # Net::SSH::Buffer is a flexible class for building and parsing binary
10
- # data packets. It provides a stream-like interface for sequentially
11
- # reading data items from the buffer, as well as a useful helper method
12
- # for building binary packets given a signature.
13
- #
14
- # Writing to a buffer always appends to the end, regardless of where the
15
- # read cursor is. Reading, on the other hand, always begins at the first
16
- # byte of the buffer and increments the read cursor, with subsequent reads
17
- # taking up where the last left off.
18
- #
19
- # As a consumer of the Net::SSH library, you will rarely come into contact
20
- # with these buffer objects directly, but it could happen. Also, if you
21
- # are ever implementing a protocol on top of SSH (e.g. SFTP), this buffer
22
- # class can be quite handy.
23
- class Buffer
24
- # This is a convenience method for creating and populating a new buffer
25
- # from a single command. The arguments must be even in length, with the
26
- # first of each pair of arguments being a symbol naming the type of the
27
- # data that follows. If the type is :raw, the value is written directly
28
- # to the hash.
29
- #
30
- # b = Buffer.from(:byte, 1, :string, "hello", :raw, "\1\2\3\4")
31
- # #-> "\1\0\0\0\5hello\1\2\3\4"
32
- #
33
- # The supported data types are:
7
+ module Net
8
+ module SSH
9
+
10
+ # Net::SSH::Buffer is a flexible class for building and parsing binary
11
+ # data packets. It provides a stream-like interface for sequentially
12
+ # reading data items from the buffer, as well as a useful helper method
13
+ # for building binary packets given a signature.
34
14
  #
35
- # * :raw => write the next value verbatim (#write)
36
- # * :int64 => write an 8-byte integer (#write_int64)
37
- # * :long => write a 4-byte integer (#write_long)
38
- # * :byte => write a single byte (#write_byte)
39
- # * :string => write a 4-byte length followed by character data (#write_string)
40
- # * :mstring => same as string, but caller cannot resuse the string, avoids potential duplication (#write_moved)
41
- # * :bool => write a single byte, interpreted as a boolean (#write_bool)
42
- # * :bignum => write an SSH-encoded bignum (#write_bignum)
43
- # * :key => write an SSH-encoded key value (#write_key)
15
+ # Writing to a buffer always appends to the end, regardless of where the
16
+ # read cursor is. Reading, on the other hand, always begins at the first
17
+ # byte of the buffer and increments the read cursor, with subsequent reads
18
+ # taking up where the last left off.
44
19
  #
45
- # Any of these, except for :raw, accepts an Array argument, to make it
46
- # easier to write multiple values of the same type in a briefer manner.
47
- def self.from(*args)
48
- raise ArgumentError, "odd number of arguments given" unless args.length % 2 == 0
49
-
50
- buffer = new
51
- 0.step(args.length-1, 2) do |index|
52
- type = args[index]
53
- value = args[index+1]
54
- if type == :raw
55
- buffer.append(value.to_s)
56
- elsif Array === value
57
- buffer.send("write_#{type}", *value)
58
- else
59
- buffer.send("write_#{type}", value)
20
+ # As a consumer of the Net::SSH library, you will rarely come into contact
21
+ # with these buffer objects directly, but it could happen. Also, if you
22
+ # are ever implementing a protocol on top of SSH (e.g. SFTP), this buffer
23
+ # class can be quite handy.
24
+ class Buffer
25
+ # This is a convenience method for creating and populating a new buffer
26
+ # from a single command. The arguments must be even in length, with the
27
+ # first of each pair of arguments being a symbol naming the type of the
28
+ # data that follows. If the type is :raw, the value is written directly
29
+ # to the hash.
30
+ #
31
+ # b = Buffer.from(:byte, 1, :string, "hello", :raw, "\1\2\3\4")
32
+ # #-> "\1\0\0\0\5hello\1\2\3\4"
33
+ #
34
+ # The supported data types are:
35
+ #
36
+ # * :raw => write the next value verbatim (#write)
37
+ # * :int64 => write an 8-byte integer (#write_int64)
38
+ # * :long => write a 4-byte integer (#write_long)
39
+ # * :byte => write a single byte (#write_byte)
40
+ # * :string => write a 4-byte length followed by character data (#write_string)
41
+ # * :mstring => same as string, but caller cannot resuse the string, avoids potential duplication (#write_moved)
42
+ # * :bool => write a single byte, interpreted as a boolean (#write_bool)
43
+ # * :bignum => write an SSH-encoded bignum (#write_bignum)
44
+ # * :key => write an SSH-encoded key value (#write_key)
45
+ #
46
+ # Any of these, except for :raw, accepts an Array argument, to make it
47
+ # easier to write multiple values of the same type in a briefer manner.
48
+ def self.from(*args)
49
+ raise ArgumentError, "odd number of arguments given" unless args.length % 2 == 0
50
+
51
+ buffer = new
52
+ 0.step(args.length - 1, 2) do |index|
53
+ type = args[index]
54
+ value = args[index + 1]
55
+ if type == :raw
56
+ buffer.append(value.to_s)
57
+ elsif Array === value
58
+ buffer.send("write_#{type}", *value)
59
+ else
60
+ buffer.send("write_#{type}", value)
61
+ end
60
62
  end
61
- end
62
63
 
63
- buffer
64
- end
64
+ buffer
65
+ end
65
66
 
66
- # exposes the raw content of the buffer
67
- attr_reader :content
67
+ # exposes the raw content of the buffer
68
+ attr_reader :content
68
69
 
69
- # the current position of the pointer in the buffer
70
- attr_accessor :position
70
+ # the current position of the pointer in the buffer
71
+ attr_accessor :position
71
72
 
72
- # Creates a new buffer, initialized to the given content. The position
73
- # is initialized to the beginning of the buffer.
74
- def initialize(content="")
75
- @content = content.to_s
76
- @position = 0
77
- end
73
+ # Creates a new buffer, initialized to the given content. The position
74
+ # is initialized to the beginning of the buffer.
75
+ def initialize(content="")
76
+ @content = content.to_s
77
+ @position = 0
78
+ end
78
79
 
79
- # Returns the length of the buffer's content.
80
- def length
81
- @content.length
82
- end
80
+ # Returns the length of the buffer's content.
81
+ def length
82
+ @content.length
83
+ end
83
84
 
84
- # Returns the number of bytes available to be read (e.g., how many bytes
85
- # remain between the current position and the end of the buffer).
86
- def available
87
- length - position
88
- end
85
+ # Returns the number of bytes available to be read (e.g., how many bytes
86
+ # remain between the current position and the end of the buffer).
87
+ def available
88
+ length - position
89
+ end
89
90
 
90
- # Returns a copy of the buffer's content.
91
- def to_s
92
- (@content || "").dup
93
- end
91
+ # Returns a copy of the buffer's content.
92
+ def to_s
93
+ (@content || "").dup
94
+ end
94
95
 
95
- # Compares the contents of the two buffers, returning +true+ only if they
96
- # are identical in size and content.
97
- def ==(buffer)
98
- to_s == buffer.to_s
99
- end
96
+ # Compares the contents of the two buffers, returning +true+ only if they
97
+ # are identical in size and content.
98
+ def ==(buffer)
99
+ to_s == buffer.to_s
100
+ end
100
101
 
101
- # Returns +true+ if the buffer contains no data (e.g., it is of zero length).
102
- def empty?
103
- @content.empty?
104
- end
102
+ # Returns +true+ if the buffer contains no data (e.g., it is of zero length).
103
+ def empty?
104
+ @content.empty?
105
+ end
105
106
 
106
- # Resets the pointer to the start of the buffer. Subsequent reads will
107
- # begin at position 0.
108
- def reset!
109
- @position = 0
110
- end
107
+ # Resets the pointer to the start of the buffer. Subsequent reads will
108
+ # begin at position 0.
109
+ def reset!
110
+ @position = 0
111
+ end
111
112
 
112
- # Returns true if the pointer is at the end of the buffer. Subsequent
113
- # reads will return nil, in this case.
114
- def eof?
115
- @position >= length
116
- end
113
+ # Returns true if the pointer is at the end of the buffer. Subsequent
114
+ # reads will return nil, in this case.
115
+ def eof?
116
+ @position >= length
117
+ end
117
118
 
118
- # Resets the buffer, making it empty. Also, resets the read position to
119
- # 0.
120
- def clear!
121
- @content = ""
122
- @position = 0
123
- end
119
+ # Resets the buffer, making it empty. Also, resets the read position to
120
+ # 0.
121
+ def clear!
122
+ @content = ""
123
+ @position = 0
124
+ end
124
125
 
125
- # Consumes n bytes from the buffer, where n is the current position
126
- # unless otherwise specified. This is useful for removing data from the
127
- # buffer that has previously been read, when you are expecting more data
128
- # to be appended. It helps to keep the size of buffers down when they
129
- # would otherwise tend to grow without bound.
130
- #
131
- # Returns the buffer object itself.
132
- def consume!(n=position)
133
- if n >= length
134
- # optimize for a fairly common case
135
- clear!
136
- elsif n > 0
137
- @content = @content[n..-1] || ""
138
- @position -= n
139
- @position = 0 if @position < 0
140
- end
141
- self
142
- end
126
+ # Consumes n bytes from the buffer, where n is the current position
127
+ # unless otherwise specified. This is useful for removing data from the
128
+ # buffer that has previously been read, when you are expecting more data
129
+ # to be appended. It helps to keep the size of buffers down when they
130
+ # would otherwise tend to grow without bound.
131
+ #
132
+ # Returns the buffer object itself.
133
+ def consume!(n=position)
134
+ if n >= length
135
+ # optimize for a fairly common case
136
+ clear!
137
+ elsif n > 0
138
+ @content = @content[n..-1] || ""
139
+ @position -= n
140
+ @position = 0 if @position < 0
141
+ end
142
+ self
143
+ end
143
144
 
144
- # Appends the given text to the end of the buffer. Does not alter the
145
- # read position. Returns the buffer object itself.
146
- def append(text)
147
- @content << text
148
- self
149
- end
145
+ # Appends the given text to the end of the buffer. Does not alter the
146
+ # read position. Returns the buffer object itself.
147
+ def append(text)
148
+ @content << text
149
+ self
150
+ end
150
151
 
151
- # Returns all text from the current pointer to the end of the buffer as
152
- # a new Net::SSH::Buffer object.
153
- def remainder_as_buffer
154
- Buffer.new(@content[@position..-1])
155
- end
152
+ # Returns all text from the current pointer to the end of the buffer as
153
+ # a new Net::SSH::Buffer object.
154
+ def remainder_as_buffer
155
+ Buffer.new(@content[@position..-1])
156
+ end
156
157
 
157
- # Reads all data up to and including the given pattern, which may be a
158
- # String, Fixnum, or Regexp and is interpreted exactly as String#index
159
- # does. Returns nil if nothing matches. Increments the position to point
160
- # immediately after the pattern, if it does match. Returns all data up to
161
- # and including the text that matched the pattern.
162
- def read_to(pattern)
163
- index = @content.index(pattern, @position) or return nil
164
- length = case pattern
165
- when String then pattern.length
166
- when Integer then 1
167
- when Regexp then $&.length
168
- end
169
- index && read(index+length)
170
- end
158
+ # Reads all data up to and including the given pattern, which may be a
159
+ # String, Fixnum, or Regexp and is interpreted exactly as String#index
160
+ # does. Returns nil if nothing matches. Increments the position to point
161
+ # immediately after the pattern, if it does match. Returns all data up to
162
+ # and including the text that matched the pattern.
163
+ def read_to(pattern)
164
+ index = @content.index(pattern, @position) or return nil
165
+ length = case pattern
166
+ when String then pattern.length
167
+ when Integer then 1
168
+ when Regexp then $&.length
169
+ end
170
+ index && read(index + length)
171
+ end
171
172
 
172
- # Reads and returns the next +count+ bytes from the buffer, starting from
173
- # the read position. If +count+ is +nil+, this will return all remaining
174
- # text in the buffer. This method will increment the pointer.
175
- def read(count=nil)
176
- count ||= length
177
- count = length - @position if @position + count > length
178
- @position += count
179
- @content[@position-count, count]
180
- end
173
+ # Reads and returns the next +count+ bytes from the buffer, starting from
174
+ # the read position. If +count+ is +nil+, this will return all remaining
175
+ # text in the buffer. This method will increment the pointer.
176
+ def read(count=nil)
177
+ count ||= length
178
+ count = length - @position if @position + count > length
179
+ @position += count
180
+ @content[@position - count, count]
181
+ end
181
182
 
182
- # Reads (as #read) and returns the given number of bytes from the buffer,
183
- # and then consumes (as #consume!) all data up to the new read position.
184
- def read!(count=nil)
185
- data = read(count)
186
- consume!
187
- data
188
- end
183
+ # Reads (as #read) and returns the given number of bytes from the buffer,
184
+ # and then consumes (as #consume!) all data up to the new read position.
185
+ def read!(count=nil)
186
+ data = read(count)
187
+ consume!
188
+ data
189
+ end
189
190
 
190
- # Calls block(self) until the buffer is empty, and returns all results.
191
- def read_all(&block)
192
- Enumerator.new { |e| e << yield(self) until eof? }.to_a
193
- end
191
+ # Calls block(self) until the buffer is empty, and returns all results.
192
+ def read_all(&block)
193
+ Enumerator.new { |e| e << yield(self) until eof? }.to_a
194
+ end
194
195
 
195
- # Return the next 8 bytes as a 64-bit integer (in network byte order).
196
- # Returns nil if there are less than 8 bytes remaining to be read in the
197
- # buffer.
198
- def read_int64
199
- hi = read_long or return nil
200
- lo = read_long or return nil
201
- return (hi << 32) + lo
202
- end
196
+ # Return the next 8 bytes as a 64-bit integer (in network byte order).
197
+ # Returns nil if there are less than 8 bytes remaining to be read in the
198
+ # buffer.
199
+ def read_int64
200
+ hi = read_long or return nil
201
+ lo = read_long or return nil
202
+ return (hi << 32) + lo
203
+ end
203
204
 
204
- # Return the next four bytes as a long integer (in network byte order).
205
- # Returns nil if there are less than 4 bytes remaining to be read in the
206
- # buffer.
207
- def read_long
208
- b = read(4) or return nil
209
- b.unpack("N").first
210
- end
205
+ # Return the next four bytes as a long integer (in network byte order).
206
+ # Returns nil if there are less than 4 bytes remaining to be read in the
207
+ # buffer.
208
+ def read_long
209
+ b = read(4) or return nil
210
+ b.unpack("N").first
211
+ end
211
212
 
212
- # Read and return the next byte in the buffer. Returns nil if called at
213
- # the end of the buffer.
214
- def read_byte
215
- b = read(1) or return nil
216
- b.getbyte(0)
217
- end
213
+ # Read and return the next byte in the buffer. Returns nil if called at
214
+ # the end of the buffer.
215
+ def read_byte
216
+ b = read(1) or return nil
217
+ b.getbyte(0)
218
+ end
218
219
 
219
- # Read and return an SSH2-encoded string. The string starts with a long
220
- # integer that describes the number of bytes remaining in the string.
221
- # Returns nil if there are not enough bytes to satisfy the request.
222
- def read_string
223
- length = read_long or return nil
224
- read(length)
225
- end
220
+ # Read and return an SSH2-encoded string. The string starts with a long
221
+ # integer that describes the number of bytes remaining in the string.
222
+ # Returns nil if there are not enough bytes to satisfy the request.
223
+ def read_string
224
+ length = read_long or return nil
225
+ read(length)
226
+ end
226
227
 
227
- # Read a single byte and convert it into a boolean, using 'C' rules
228
- # (i.e., zero is false, non-zero is true).
229
- def read_bool
230
- b = read_byte or return nil
231
- b != 0
232
- end
228
+ # Read a single byte and convert it into a boolean, using 'C' rules
229
+ # (i.e., zero is false, non-zero is true).
230
+ def read_bool
231
+ b = read_byte or return nil
232
+ b != 0
233
+ end
233
234
 
234
- # Read a bignum (OpenSSL::BN) from the buffer, in SSH2 format. It is
235
- # essentially just a string, which is reinterpreted to be a bignum in
236
- # binary format.
237
- def read_bignum
238
- data = read_string
239
- return unless data
240
- OpenSSL::BN.new(data, 2)
241
- end
235
+ # Read a bignum (OpenSSL::BN) from the buffer, in SSH2 format. It is
236
+ # essentially just a string, which is reinterpreted to be a bignum in
237
+ # binary format.
238
+ def read_bignum
239
+ data = read_string
240
+ return unless data
241
+ OpenSSL::BN.new(data, 2)
242
+ end
242
243
 
243
- # Read a key from the buffer. The key will start with a string
244
- # describing its type. The remainder of the key is defined by the
245
- # type that was read.
246
- def read_key
247
- type = read_string
248
- return (type ? read_keyblob(type) : nil)
249
- end
244
+ # Read a key from the buffer. The key will start with a string
245
+ # describing its type. The remainder of the key is defined by the
246
+ # type that was read.
247
+ def read_key
248
+ type = read_string
249
+ return (type ? read_keyblob(type) : nil)
250
+ end
250
251
 
251
- # Read a keyblob of the given type from the buffer, and return it as
252
- # a key. Only RSA, DSA, and ECDSA keys are supported.
253
- def read_keyblob(type)
254
- case type
252
+ # Read a keyblob of the given type from the buffer, and return it as
253
+ # a key. Only RSA, DSA, and ECDSA keys are supported.
254
+ def read_keyblob(type)
255
+ case type
255
256
  when /^(.*)-cert-v01@openssh\.com$/
256
257
  key = Net::SSH::Authentication::Certificate.read_certblob(self, $1)
257
258
  when /^ssh-dss$/
@@ -293,104 +294,105 @@ module Net; module SSH
293
294
  end
294
295
  else
295
296
  raise NotImplementedError, "unsupported key type `#{type}'"
296
- end
297
+ end
297
298
 
298
- return key
299
- end
299
+ return key
300
+ end
300
301
 
301
- # Reads the next string from the buffer, and returns a new Buffer
302
- # object that wraps it.
303
- def read_buffer
304
- Buffer.new(read_string)
305
- end
302
+ # Reads the next string from the buffer, and returns a new Buffer
303
+ # object that wraps it.
304
+ def read_buffer
305
+ Buffer.new(read_string)
306
+ end
306
307
 
307
- # Writes the given data literally into the string. Does not alter the
308
- # read position. Returns the buffer object.
309
- def write(*data)
310
- data.each { |datum| @content << datum.dup.force_encoding('BINARY') }
311
- self
312
- end
308
+ # Writes the given data literally into the string. Does not alter the
309
+ # read position. Returns the buffer object.
310
+ def write(*data)
311
+ data.each { |datum| @content << datum.dup.force_encoding('BINARY') }
312
+ self
313
+ end
313
314
 
314
- # Optimized version of write where the caller gives up ownership of string
315
- # to the method. This way we can mutate the string.
316
- def write_moved(string)
317
- @content << string.force_encoding('BINARY')
318
- self
319
- end
315
+ # Optimized version of write where the caller gives up ownership of string
316
+ # to the method. This way we can mutate the string.
317
+ def write_moved(string)
318
+ @content << string.force_encoding('BINARY')
319
+ self
320
+ end
320
321
 
321
- # Writes each argument to the buffer as a network-byte-order-encoded
322
- # 64-bit integer (8 bytes). Does not alter the read position. Returns the
323
- # buffer object.
324
- def write_int64(*n)
325
- n.each do |i|
326
- hi = (i >> 32) & 0xFFFFFFFF
327
- lo = i & 0xFFFFFFFF
328
- @content << [hi, lo].pack("N2")
322
+ # Writes each argument to the buffer as a network-byte-order-encoded
323
+ # 64-bit integer (8 bytes). Does not alter the read position. Returns the
324
+ # buffer object.
325
+ def write_int64(*n)
326
+ n.each do |i|
327
+ hi = (i >> 32) & 0xFFFFFFFF
328
+ lo = i & 0xFFFFFFFF
329
+ @content << [hi, lo].pack("N2")
330
+ end
331
+ self
329
332
  end
330
- self
331
- end
332
333
 
333
- # Writes each argument to the buffer as a network-byte-order-encoded
334
- # long (4-byte) integer. Does not alter the read position. Returns the
335
- # buffer object.
336
- def write_long(*n)
337
- @content << n.pack("N*")
338
- self
339
- end
334
+ # Writes each argument to the buffer as a network-byte-order-encoded
335
+ # long (4-byte) integer. Does not alter the read position. Returns the
336
+ # buffer object.
337
+ def write_long(*n)
338
+ @content << n.pack("N*")
339
+ self
340
+ end
340
341
 
341
- # Writes each argument to the buffer as a byte. Does not alter the read
342
- # position. Returns the buffer object.
343
- def write_byte(*n)
344
- n.each { |b| @content << b.chr }
345
- self
346
- end
342
+ # Writes each argument to the buffer as a byte. Does not alter the read
343
+ # position. Returns the buffer object.
344
+ def write_byte(*n)
345
+ n.each { |b| @content << b.chr }
346
+ self
347
+ end
347
348
 
348
- # Writes each argument to the buffer as an SSH2-encoded string. Each
349
- # string is prefixed by its length, encoded as a 4-byte long integer.
350
- # Does not alter the read position. Returns the buffer object.
351
- def write_string(*text)
352
- text.each do |string|
353
- s = string.to_s
354
- write_long(s.bytesize)
355
- write(s)
349
+ # Writes each argument to the buffer as an SSH2-encoded string. Each
350
+ # string is prefixed by its length, encoded as a 4-byte long integer.
351
+ # Does not alter the read position. Returns the buffer object.
352
+ def write_string(*text)
353
+ text.each do |string|
354
+ s = string.to_s
355
+ write_long(s.bytesize)
356
+ write(s)
357
+ end
358
+ self
356
359
  end
357
- self
358
- end
359
360
 
360
- # Writes each argument to the buffer as an SSH2-encoded string. Each
361
- # string is prefixed by its length, encoded as a 4-byte long integer.
362
- # Does not alter the read position. Returns the buffer object.
363
- # Might alter arguments see write_moved
364
- def write_mstring(*text)
365
- text.each do |string|
366
- s = string.to_s
367
- write_long(s.bytesize)
368
- write_moved(s)
369
- end
370
- self
371
- end
361
+ # Writes each argument to the buffer as an SSH2-encoded string. Each
362
+ # string is prefixed by its length, encoded as a 4-byte long integer.
363
+ # Does not alter the read position. Returns the buffer object.
364
+ # Might alter arguments see write_moved
365
+ def write_mstring(*text)
366
+ text.each do |string|
367
+ s = string.to_s
368
+ write_long(s.bytesize)
369
+ write_moved(s)
370
+ end
371
+ self
372
+ end
372
373
 
373
- # Writes each argument to the buffer as a (C-style) boolean, with 1
374
- # meaning true, and 0 meaning false. Does not alter the read position.
375
- # Returns the buffer object.
376
- def write_bool(*b)
377
- b.each { |v| @content << (v ? "\1" : "\0") }
378
- self
379
- end
374
+ # Writes each argument to the buffer as a (C-style) boolean, with 1
375
+ # meaning true, and 0 meaning false. Does not alter the read position.
376
+ # Returns the buffer object.
377
+ def write_bool(*b)
378
+ b.each { |v| @content << (v ? "\1" : "\0") }
379
+ self
380
+ end
380
381
 
381
- # Writes each argument to the buffer as a bignum (SSH2-style). No
382
- # checking is done to ensure that the arguments are, in fact, bignums.
383
- # Does not alter the read position. Returns the buffer object.
384
- def write_bignum(*n)
385
- @content << n.map { |b| b.to_ssh }.join
386
- self
387
- end
382
+ # Writes each argument to the buffer as a bignum (SSH2-style). No
383
+ # checking is done to ensure that the arguments are, in fact, bignums.
384
+ # Does not alter the read position. Returns the buffer object.
385
+ def write_bignum(*n)
386
+ @content << n.map { |b| b.to_ssh }.join
387
+ self
388
+ end
388
389
 
389
- # Writes the given arguments to the buffer as SSH2-encoded keys. Does not
390
- # alter the read position. Returns the buffer object.
391
- def write_key(*key)
392
- key.each { |k| append(k.to_blob) }
393
- self
390
+ # Writes the given arguments to the buffer as SSH2-encoded keys. Does not
391
+ # alter the read position. Returns the buffer object.
392
+ def write_key(*key)
393
+ key.each { |k| append(k.to_blob) }
394
+ self
395
+ end
394
396
  end
395
397
  end
396
- end; end;
398
+ end;