net-ssh-net-ssh 2.0.12
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 +137 -0
- data/Manifest +104 -0
- data/README.rdoc +110 -0
- data/Rakefile +79 -0
- data/THANKS.rdoc +16 -0
- data/lib/net/ssh.rb +215 -0
- data/lib/net/ssh/authentication/agent.rb +176 -0
- data/lib/net/ssh/authentication/constants.rb +18 -0
- data/lib/net/ssh/authentication/key_manager.rb +193 -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 +183 -0
- data/lib/net/ssh/authentication/session.rb +134 -0
- data/lib/net/ssh/buffer.rb +340 -0
- data/lib/net/ssh/buffered_io.rb +149 -0
- data/lib/net/ssh/config.rb +181 -0
- data/lib/net/ssh/connection/channel.rb +625 -0
- data/lib/net/ssh/connection/constants.rb +33 -0
- data/lib/net/ssh/connection/session.rb +596 -0
- data/lib/net/ssh/connection/term.rb +178 -0
- data/lib/net/ssh/errors.rb +85 -0
- data/lib/net/ssh/key_factory.rb +102 -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 +14 -0
- data/lib/net/ssh/proxy/http.rb +94 -0
- data/lib/net/ssh/proxy/socks4.rb +70 -0
- data/lib/net/ssh/proxy/socks5.rb +129 -0
- data/lib/net/ssh/ruby_compat.rb +7 -0
- 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 +84 -0
- data/lib/net/ssh/transport/constants.rb +30 -0
- data/lib/net/ssh/transport/hmac.rb +31 -0
- data/lib/net/ssh/transport/hmac/abstract.rb +78 -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 +55 -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/transport/openssl.rb +128 -0
- data/lib/net/ssh/transport/packet_stream.rb +230 -0
- data/lib/net/ssh/transport/server_version.rb +69 -0
- data/lib/net/ssh/transport/session.rb +276 -0
- data/lib/net/ssh/transport/state.rb +206 -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 +62 -0
- data/net-ssh.gemspec +128 -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 +114 -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 +127 -0
- data/test/authentication/test_agent.rb +205 -0
- data/test/authentication/test_key_manager.rb +105 -0
- data/test/authentication/test_session.rb +93 -0
- data/test/common.rb +106 -0
- data/test/configs/eqsign +3 -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 +488 -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 +84 -0
- data/test/test_key_factory.rb +67 -0
- data/test/transport/hmac/test_md5.rb +39 -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 +171 -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 +435 -0
- data/test/transport/test_server_version.rb +68 -0
- data/test/transport/test_session.rb +315 -0
- data/test/transport/test_state.rb +173 -0
- metadata +162 -0
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'net/ssh/loggable'
|
2
|
+
require 'net/ssh/transport/constants'
|
3
|
+
require 'net/ssh/authentication/constants'
|
4
|
+
require 'net/ssh/authentication/key_manager'
|
5
|
+
require 'net/ssh/authentication/methods/publickey'
|
6
|
+
require 'net/ssh/authentication/methods/hostbased'
|
7
|
+
require 'net/ssh/authentication/methods/password'
|
8
|
+
require 'net/ssh/authentication/methods/keyboard_interactive'
|
9
|
+
|
10
|
+
module Net; module SSH; module Authentication
|
11
|
+
|
12
|
+
# Represents an authentication session. It manages the authentication of
|
13
|
+
# a user over an established connection (the "transport" object, see
|
14
|
+
# Net::SSH::Transport::Session).
|
15
|
+
#
|
16
|
+
# The use of an authentication session to manage user authentication is
|
17
|
+
# internal to Net::SSH (specifically Net::SSH.start). Consumers of the
|
18
|
+
# Net::SSH library will never need to access this class directly.
|
19
|
+
class Session
|
20
|
+
include Transport::Constants, Constants, Loggable
|
21
|
+
|
22
|
+
# transport layer abstraction
|
23
|
+
attr_reader :transport
|
24
|
+
|
25
|
+
# the list of authentication methods to try
|
26
|
+
attr_reader :auth_methods
|
27
|
+
|
28
|
+
# the list of authentication methods that are allowed
|
29
|
+
attr_reader :allowed_auth_methods
|
30
|
+
|
31
|
+
# a hash of options, given at construction time
|
32
|
+
attr_reader :options
|
33
|
+
|
34
|
+
# Instantiates a new Authentication::Session object over the given
|
35
|
+
# transport layer abstraction.
|
36
|
+
def initialize(transport, options={})
|
37
|
+
self.logger = transport.logger
|
38
|
+
@transport = transport
|
39
|
+
|
40
|
+
@auth_methods = options[:auth_methods] || %w(publickey hostbased password keyboard-interactive)
|
41
|
+
@options = options
|
42
|
+
|
43
|
+
@allowed_auth_methods = @auth_methods
|
44
|
+
end
|
45
|
+
|
46
|
+
# Attempts to authenticate the given user, in preparation for the next
|
47
|
+
# service request. Returns true if an authentication method succeeds in
|
48
|
+
# authenticating the user, and false otherwise.
|
49
|
+
def authenticate(next_service, username, password=nil)
|
50
|
+
debug { "beginning authentication of `#{username}'" }
|
51
|
+
|
52
|
+
transport.send_message(transport.service_request("ssh-userauth"))
|
53
|
+
message = expect_message(SERVICE_ACCEPT)
|
54
|
+
|
55
|
+
key_manager = KeyManager.new(logger, options)
|
56
|
+
keys.each { |key| key_manager.add(key) } unless keys.empty?
|
57
|
+
key_data.each { |key2| key_manager.add_key_data(key2) } unless key_data.empty?
|
58
|
+
|
59
|
+
attempted = []
|
60
|
+
|
61
|
+
@auth_methods.each do |name|
|
62
|
+
next unless @allowed_auth_methods.include?(name)
|
63
|
+
attempted << name
|
64
|
+
|
65
|
+
debug { "trying #{name}" }
|
66
|
+
method = Methods.const_get(name.split(/\W+/).map { |p| p.capitalize }.join).new(self, :key_manager => key_manager)
|
67
|
+
|
68
|
+
return true if method.authenticate(next_service, username, password)
|
69
|
+
end
|
70
|
+
|
71
|
+
error { "all authorization methods failed (tried #{attempted.join(', ')})" }
|
72
|
+
return false
|
73
|
+
ensure
|
74
|
+
key_manager.finish if key_manager
|
75
|
+
end
|
76
|
+
|
77
|
+
# Blocks until a packet is received. It silently handles USERAUTH_BANNER
|
78
|
+
# packets, and will raise an error if any packet is received that is not
|
79
|
+
# valid during user authentication.
|
80
|
+
def next_message
|
81
|
+
loop do
|
82
|
+
packet = transport.next_message
|
83
|
+
|
84
|
+
case packet.type
|
85
|
+
when USERAUTH_BANNER
|
86
|
+
info { packet[:message] }
|
87
|
+
# TODO add a hook for people to retrieve the banner when it is sent
|
88
|
+
|
89
|
+
when USERAUTH_FAILURE
|
90
|
+
@allowed_auth_methods = packet[:authentications].split(/,/)
|
91
|
+
debug { "allowed methods: #{packet[:authentications]}" }
|
92
|
+
return packet
|
93
|
+
|
94
|
+
when USERAUTH_METHOD_RANGE, SERVICE_ACCEPT
|
95
|
+
return packet
|
96
|
+
|
97
|
+
when USERAUTH_SUCCESS
|
98
|
+
transport.hint :authenticated
|
99
|
+
return packet
|
100
|
+
|
101
|
+
else
|
102
|
+
raise Net::SSH::Exception, "unexpected message #{packet.type} (#{packet})"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Blocks until a packet is received, and returns it if it is of the given
|
108
|
+
# type. If it is not, an exception is raised.
|
109
|
+
def expect_message(type)
|
110
|
+
message = next_message
|
111
|
+
unless message.type == type
|
112
|
+
raise Net::SSH::Exception, "expected #{type}, got #{message.type} (#{message})"
|
113
|
+
end
|
114
|
+
message
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
# Returns an array of paths to the key files that should be used when
|
120
|
+
# attempting any key-based authentication mechanism.
|
121
|
+
def keys
|
122
|
+
Array(
|
123
|
+
options[:keys] ||
|
124
|
+
%w(~/.ssh/id_dsa ~/.ssh/id_rsa ~/.ssh2/id_dsa ~/.ssh2/id_rsa)
|
125
|
+
)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Returns an array of the key data that should be used when
|
129
|
+
# attempting any key-based authentication mechanism.
|
130
|
+
def key_data
|
131
|
+
Array(options[:key_data])
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end; end; end
|
@@ -0,0 +1,340 @@
|
|
1
|
+
require 'net/ssh/ruby_compat'
|
2
|
+
require 'net/ssh/transport/openssl'
|
3
|
+
|
4
|
+
module Net; module SSH
|
5
|
+
|
6
|
+
# Net::SSH::Buffer is a flexible class for building and parsing binary
|
7
|
+
# data packets. It provides a stream-like interface for sequentially
|
8
|
+
# reading data items from the buffer, as well as a useful helper method
|
9
|
+
# for building binary packets given a signature.
|
10
|
+
#
|
11
|
+
# Writing to a buffer always appends to the end, regardless of where the
|
12
|
+
# read cursor is. Reading, on the other hand, always begins at the first
|
13
|
+
# byte of the buffer and increments the read cursor, with subsequent reads
|
14
|
+
# taking up where the last left off.
|
15
|
+
#
|
16
|
+
# As a consumer of the Net::SSH library, you will rarely come into contact
|
17
|
+
# with these buffer objects directly, but it could happen. Also, if you
|
18
|
+
# are ever implementing a protocol on top of SSH (e.g. SFTP), this buffer
|
19
|
+
# class can be quite handy.
|
20
|
+
class Buffer
|
21
|
+
# This is a convenience method for creating and populating a new buffer
|
22
|
+
# from a single command. The arguments must be even in length, with the
|
23
|
+
# first of each pair of arguments being a symbol naming the type of the
|
24
|
+
# data that follows. If the type is :raw, the value is written directly
|
25
|
+
# to the hash.
|
26
|
+
#
|
27
|
+
# b = Buffer.from(:byte, 1, :string, "hello", :raw, "\1\2\3\4")
|
28
|
+
# #-> "\1\0\0\0\5hello\1\2\3\4"
|
29
|
+
#
|
30
|
+
# The supported data types are:
|
31
|
+
#
|
32
|
+
# * :raw => write the next value verbatim (#write)
|
33
|
+
# * :int64 => write an 8-byte integer (#write_int64)
|
34
|
+
# * :long => write a 4-byte integer (#write_long)
|
35
|
+
# * :byte => write a single byte (#write_byte)
|
36
|
+
# * :string => write a 4-byte length followed by character data (#write_string)
|
37
|
+
# * :bool => write a single byte, interpreted as a boolean (#write_bool)
|
38
|
+
# * :bignum => write an SSH-encoded bignum (#write_bignum)
|
39
|
+
# * :key => write an SSH-encoded key value (#write_key)
|
40
|
+
#
|
41
|
+
# Any of these, except for :raw, accepts an Array argument, to make it
|
42
|
+
# easier to write multiple values of the same type in a briefer manner.
|
43
|
+
def self.from(*args)
|
44
|
+
raise ArgumentError, "odd number of arguments given" unless args.length % 2 == 0
|
45
|
+
|
46
|
+
buffer = new
|
47
|
+
0.step(args.length-1, 2) do |index|
|
48
|
+
type = args[index]
|
49
|
+
value = args[index+1]
|
50
|
+
if type == :raw
|
51
|
+
buffer.append(value.to_s)
|
52
|
+
elsif Array === value
|
53
|
+
buffer.send("write_#{type}", *value)
|
54
|
+
else
|
55
|
+
buffer.send("write_#{type}", value)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
buffer
|
60
|
+
end
|
61
|
+
|
62
|
+
# exposes the raw content of the buffer
|
63
|
+
attr_reader :content
|
64
|
+
|
65
|
+
# the current position of the pointer in the buffer
|
66
|
+
attr_accessor :position
|
67
|
+
|
68
|
+
# Creates a new buffer, initialized to the given content. The position
|
69
|
+
# is initialized to the beginning of the buffer.
|
70
|
+
def initialize(content="")
|
71
|
+
@content = content.to_s
|
72
|
+
@position = 0
|
73
|
+
end
|
74
|
+
|
75
|
+
# Returns the length of the buffer's content.
|
76
|
+
def length
|
77
|
+
@content.length
|
78
|
+
end
|
79
|
+
|
80
|
+
# Returns the number of bytes available to be read (e.g., how many bytes
|
81
|
+
# remain between the current position and the end of the buffer).
|
82
|
+
def available
|
83
|
+
length - position
|
84
|
+
end
|
85
|
+
|
86
|
+
# Returns a copy of the buffer's content.
|
87
|
+
def to_s
|
88
|
+
(@content || "").dup
|
89
|
+
end
|
90
|
+
|
91
|
+
# Compares the contents of the two buffers, returning +true+ only if they
|
92
|
+
# are identical in size and content.
|
93
|
+
def ==(buffer)
|
94
|
+
to_s == buffer.to_s
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns +true+ if the buffer contains no data (e.g., it is of zero length).
|
98
|
+
def empty?
|
99
|
+
@content.empty?
|
100
|
+
end
|
101
|
+
|
102
|
+
# Resets the pointer to the start of the buffer. Subsequent reads will
|
103
|
+
# begin at position 0.
|
104
|
+
def reset!
|
105
|
+
@position = 0
|
106
|
+
end
|
107
|
+
|
108
|
+
# Returns true if the pointer is at the end of the buffer. Subsequent
|
109
|
+
# reads will return nil, in this case.
|
110
|
+
def eof?
|
111
|
+
@position >= length
|
112
|
+
end
|
113
|
+
|
114
|
+
# Resets the buffer, making it empty. Also, resets the read position to
|
115
|
+
# 0.
|
116
|
+
def clear!
|
117
|
+
@content = ""
|
118
|
+
@position = 0
|
119
|
+
end
|
120
|
+
|
121
|
+
# Consumes n bytes from the buffer, where n is the current position
|
122
|
+
# unless otherwise specified. This is useful for removing data from the
|
123
|
+
# buffer that has previously been read, when you are expecting more data
|
124
|
+
# to be appended. It helps to keep the size of buffers down when they
|
125
|
+
# would otherwise tend to grow without bound.
|
126
|
+
#
|
127
|
+
# Returns the buffer object itself.
|
128
|
+
def consume!(n=position)
|
129
|
+
if n >= length
|
130
|
+
# optimize for a fairly common case
|
131
|
+
clear!
|
132
|
+
elsif n > 0
|
133
|
+
@content = @content[n..-1] || ""
|
134
|
+
@position -= n
|
135
|
+
@position = 0 if @position < 0
|
136
|
+
end
|
137
|
+
self
|
138
|
+
end
|
139
|
+
|
140
|
+
# Appends the given text to the end of the buffer. Does not alter the
|
141
|
+
# read position. Returns the buffer object itself.
|
142
|
+
def append(text)
|
143
|
+
@content << text
|
144
|
+
self
|
145
|
+
end
|
146
|
+
|
147
|
+
# Returns all text from the current pointer to the end of the buffer as
|
148
|
+
# a new Net::SSH::Buffer object.
|
149
|
+
def remainder_as_buffer
|
150
|
+
Buffer.new(@content[@position..-1])
|
151
|
+
end
|
152
|
+
|
153
|
+
# Reads all data up to and including the given pattern, which may be a
|
154
|
+
# String, Fixnum, or Regexp and is interpreted exactly as String#index
|
155
|
+
# does. Returns nil if nothing matches. Increments the position to point
|
156
|
+
# immediately after the pattern, if it does match. Returns all data up to
|
157
|
+
# and including the text that matched the pattern.
|
158
|
+
def read_to(pattern)
|
159
|
+
index = @content.index(pattern, @position) or return nil
|
160
|
+
length = case pattern
|
161
|
+
when String then pattern.length
|
162
|
+
when Fixnum then 1
|
163
|
+
when Regexp then $&.length
|
164
|
+
end
|
165
|
+
index && read(index+length)
|
166
|
+
end
|
167
|
+
|
168
|
+
# Reads and returns the next +count+ bytes from the buffer, starting from
|
169
|
+
# the read position. If +count+ is +nil+, this will return all remaining
|
170
|
+
# text in the buffer. This method will increment the pointer.
|
171
|
+
def read(count=nil)
|
172
|
+
count ||= length
|
173
|
+
count = length - @position if @position + count > length
|
174
|
+
@position += count
|
175
|
+
@content[@position-count, count]
|
176
|
+
end
|
177
|
+
|
178
|
+
# Reads (as #read) and returns the given number of bytes from the buffer,
|
179
|
+
# and then consumes (as #consume!) all data up to the new read position.
|
180
|
+
def read!(count=nil)
|
181
|
+
data = read(count)
|
182
|
+
consume!
|
183
|
+
data
|
184
|
+
end
|
185
|
+
|
186
|
+
# Return the next 8 bytes as a 64-bit integer (in network byte order).
|
187
|
+
# Returns nil if there are less than 8 bytes remaining to be read in the
|
188
|
+
# buffer.
|
189
|
+
def read_int64
|
190
|
+
hi = read_long or return nil
|
191
|
+
lo = read_long or return nil
|
192
|
+
return (hi << 32) + lo
|
193
|
+
end
|
194
|
+
|
195
|
+
# Return the next four bytes as a long integer (in network byte order).
|
196
|
+
# Returns nil if there are less than 4 bytes remaining to be read in the
|
197
|
+
# buffer.
|
198
|
+
def read_long
|
199
|
+
b = read(4) or return nil
|
200
|
+
b.unpack("N").first
|
201
|
+
end
|
202
|
+
|
203
|
+
# Read and return the next byte in the buffer. Returns nil if called at
|
204
|
+
# the end of the buffer.
|
205
|
+
def read_byte
|
206
|
+
b = read(1) or return nil
|
207
|
+
b.getbyte(0)
|
208
|
+
end
|
209
|
+
|
210
|
+
# Read and return an SSH2-encoded string. The string starts with a long
|
211
|
+
# integer that describes the number of bytes remaining in the string.
|
212
|
+
# Returns nil if there are not enough bytes to satisfy the request.
|
213
|
+
def read_string
|
214
|
+
length = read_long or return nil
|
215
|
+
read(length)
|
216
|
+
end
|
217
|
+
|
218
|
+
# Read a single byte and convert it into a boolean, using 'C' rules
|
219
|
+
# (i.e., zero is false, non-zero is true).
|
220
|
+
def read_bool
|
221
|
+
b = read_byte or return nil
|
222
|
+
b != 0
|
223
|
+
end
|
224
|
+
|
225
|
+
# Read a bignum (OpenSSL::BN) from the buffer, in SSH2 format. It is
|
226
|
+
# essentially just a string, which is reinterpreted to be a bignum in
|
227
|
+
# binary format.
|
228
|
+
def read_bignum
|
229
|
+
data = read_string
|
230
|
+
return unless data
|
231
|
+
OpenSSL::BN.new(data, 2)
|
232
|
+
end
|
233
|
+
|
234
|
+
# Read a key from the buffer. The key will start with a string
|
235
|
+
# describing its type. The remainder of the key is defined by the
|
236
|
+
# type that was read.
|
237
|
+
def read_key
|
238
|
+
type = read_string
|
239
|
+
return (type ? read_keyblob(type) : nil)
|
240
|
+
end
|
241
|
+
|
242
|
+
# Read a keyblob of the given type from the buffer, and return it as
|
243
|
+
# a key. Only RSA and DSA keys are supported.
|
244
|
+
def read_keyblob(type)
|
245
|
+
case type
|
246
|
+
when "ssh-dss"
|
247
|
+
key = OpenSSL::PKey::DSA.new
|
248
|
+
key.p = read_bignum
|
249
|
+
key.q = read_bignum
|
250
|
+
key.g = read_bignum
|
251
|
+
key.pub_key = read_bignum
|
252
|
+
|
253
|
+
when "ssh-rsa"
|
254
|
+
key = OpenSSL::PKey::RSA.new
|
255
|
+
key.e = read_bignum
|
256
|
+
key.n = read_bignum
|
257
|
+
|
258
|
+
else
|
259
|
+
raise NotImplementedError, "unsupported key type `#{type}'"
|
260
|
+
end
|
261
|
+
|
262
|
+
return key
|
263
|
+
end
|
264
|
+
|
265
|
+
# Reads the next string from the buffer, and returns a new Buffer
|
266
|
+
# object that wraps it.
|
267
|
+
def read_buffer
|
268
|
+
Buffer.new(read_string)
|
269
|
+
end
|
270
|
+
|
271
|
+
# Writes the given data literally into the string. Does not alter the
|
272
|
+
# read position. Returns the buffer object.
|
273
|
+
def write(*data)
|
274
|
+
data.each { |datum| @content << datum }
|
275
|
+
self
|
276
|
+
end
|
277
|
+
|
278
|
+
# Writes each argument to the buffer as a network-byte-order-encoded
|
279
|
+
# 64-bit integer (8 bytes). Does not alter the read position. Returns the
|
280
|
+
# buffer object.
|
281
|
+
def write_int64(*n)
|
282
|
+
n.each do |i|
|
283
|
+
hi = (i >> 32) & 0xFFFFFFFF
|
284
|
+
lo = i & 0xFFFFFFFF
|
285
|
+
@content << [hi, lo].pack("N2")
|
286
|
+
end
|
287
|
+
self
|
288
|
+
end
|
289
|
+
|
290
|
+
# Writes each argument to the buffer as a network-byte-order-encoded
|
291
|
+
# long (4-byte) integer. Does not alter the read position. Returns the
|
292
|
+
# buffer object.
|
293
|
+
def write_long(*n)
|
294
|
+
@content << n.pack("N*")
|
295
|
+
self
|
296
|
+
end
|
297
|
+
|
298
|
+
# Writes each argument to the buffer as a byte. Does not alter the read
|
299
|
+
# position. Returns the buffer object.
|
300
|
+
def write_byte(*n)
|
301
|
+
n.each { |b| @content << b.chr }
|
302
|
+
self
|
303
|
+
end
|
304
|
+
|
305
|
+
# Writes each argument to the buffer as an SSH2-encoded string. Each
|
306
|
+
# string is prefixed by its length, encoded as a 4-byte long integer.
|
307
|
+
# Does not alter the read position. Returns the buffer object.
|
308
|
+
def write_string(*text)
|
309
|
+
text.each do |string|
|
310
|
+
s = string.to_s
|
311
|
+
write_long(s.length)
|
312
|
+
write(s)
|
313
|
+
end
|
314
|
+
self
|
315
|
+
end
|
316
|
+
|
317
|
+
# Writes each argument to the buffer as a (C-style) boolean, with 1
|
318
|
+
# meaning true, and 0 meaning false. Does not alter the read position.
|
319
|
+
# Returns the buffer object.
|
320
|
+
def write_bool(*b)
|
321
|
+
b.each { |v| @content << (v ? "\1" : "\0") }
|
322
|
+
self
|
323
|
+
end
|
324
|
+
|
325
|
+
# Writes each argument to the buffer as a bignum (SSH2-style). No
|
326
|
+
# checking is done to ensure that the arguments are, in fact, bignums.
|
327
|
+
# Does not alter the read position. Returns the buffer object.
|
328
|
+
def write_bignum(*n)
|
329
|
+
@content << n.map { |b| b.to_ssh }.join
|
330
|
+
self
|
331
|
+
end
|
332
|
+
|
333
|
+
# Writes the given arguments to the buffer as SSH2-encoded keys. Does not
|
334
|
+
# alter the read position. Returns the buffer object.
|
335
|
+
def write_key(*key)
|
336
|
+
key.each { |k| append(k.to_blob) }
|
337
|
+
self
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end; end;
|