net-ssh 1.1.4 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (297) hide show
  1. data/CHANGELOG.rdoc +37 -0
  2. data/Manifest +101 -0
  3. data/README.rdoc +110 -0
  4. data/Rakefile +26 -0
  5. data/{THANKS → THANKS.rdoc} +2 -5
  6. data/lib/net/ssh.rb +189 -57
  7. data/lib/net/ssh/authentication/agent.rb +175 -0
  8. data/lib/net/ssh/authentication/constants.rb +18 -0
  9. data/lib/net/ssh/authentication/key_manager.rb +166 -0
  10. data/lib/net/ssh/authentication/methods/abstract.rb +60 -0
  11. data/lib/net/ssh/authentication/methods/hostbased.rb +71 -0
  12. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +66 -0
  13. data/lib/net/ssh/authentication/methods/password.rb +39 -0
  14. data/lib/net/ssh/authentication/methods/publickey.rb +92 -0
  15. data/lib/net/ssh/authentication/pageant.rb +176 -0
  16. data/lib/net/ssh/authentication/session.rb +116 -0
  17. data/lib/net/ssh/buffer.rb +339 -0
  18. data/lib/net/ssh/buffered_io.rb +149 -0
  19. data/lib/net/ssh/config.rb +173 -0
  20. data/lib/net/ssh/connection/channel.rb +575 -454
  21. data/lib/net/ssh/connection/constants.rb +31 -45
  22. data/lib/net/ssh/connection/session.rb +569 -0
  23. data/lib/net/ssh/connection/term.rb +176 -88
  24. data/lib/net/ssh/errors.rb +83 -61
  25. data/lib/net/ssh/key_factory.rb +85 -0
  26. data/lib/net/ssh/known_hosts.rb +129 -0
  27. data/lib/net/ssh/loggable.rb +61 -0
  28. data/lib/net/ssh/packet.rb +102 -0
  29. data/lib/net/ssh/prompt.rb +93 -0
  30. data/lib/net/ssh/proxy/errors.rb +8 -28
  31. data/lib/net/ssh/proxy/http.rb +75 -107
  32. data/lib/net/ssh/proxy/socks4.rb +35 -48
  33. data/lib/net/ssh/proxy/socks5.rb +76 -108
  34. data/lib/net/ssh/service/forward.rb +267 -0
  35. data/lib/net/ssh/test.rb +89 -0
  36. data/lib/net/ssh/test/channel.rb +129 -0
  37. data/lib/net/ssh/test/extensions.rb +152 -0
  38. data/lib/net/ssh/test/kex.rb +44 -0
  39. data/lib/net/ssh/test/local_packet.rb +51 -0
  40. data/lib/net/ssh/test/packet.rb +81 -0
  41. data/lib/net/ssh/test/remote_packet.rb +38 -0
  42. data/lib/net/ssh/test/script.rb +157 -0
  43. data/lib/net/ssh/test/socket.rb +59 -0
  44. data/lib/net/ssh/transport/algorithms.rb +384 -0
  45. data/lib/net/ssh/transport/cipher_factory.rb +72 -0
  46. data/lib/net/ssh/transport/constants.rb +22 -58
  47. data/lib/net/ssh/transport/hmac.rb +31 -0
  48. data/lib/net/ssh/transport/hmac/abstract.rb +48 -0
  49. data/lib/net/ssh/transport/hmac/md5.rb +12 -0
  50. data/lib/net/ssh/transport/hmac/md5_96.rb +11 -0
  51. data/lib/net/ssh/transport/hmac/none.rb +15 -0
  52. data/lib/net/ssh/transport/hmac/sha1.rb +13 -0
  53. data/lib/net/ssh/transport/hmac/sha1_96.rb +11 -0
  54. data/lib/net/ssh/transport/identity_cipher.rb +40 -0
  55. data/lib/net/ssh/transport/kex.rb +13 -0
  56. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +208 -0
  57. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +77 -0
  58. data/lib/net/ssh/{util → transport}/openssl.rb +22 -40
  59. data/lib/net/ssh/transport/packet_stream.rb +230 -0
  60. data/lib/net/ssh/transport/server_version.rb +61 -0
  61. data/lib/net/ssh/transport/session.rb +225 -303
  62. data/lib/net/ssh/transport/state.rb +170 -0
  63. data/lib/net/ssh/verifiers/lenient.rb +30 -0
  64. data/lib/net/ssh/verifiers/null.rb +12 -0
  65. data/lib/net/ssh/verifiers/strict.rb +53 -0
  66. data/lib/net/ssh/version.rb +57 -26
  67. data/net-ssh.gemspec +54 -0
  68. data/setup.rb +1585 -0
  69. data/test/authentication/methods/common.rb +28 -0
  70. data/test/authentication/methods/test_abstract.rb +51 -0
  71. data/test/authentication/methods/test_hostbased.rb +108 -0
  72. data/test/authentication/methods/test_keyboard_interactive.rb +98 -0
  73. data/test/authentication/methods/test_password.rb +50 -0
  74. data/test/authentication/methods/test_publickey.rb +123 -0
  75. data/test/authentication/test_agent.rb +205 -0
  76. data/test/authentication/test_key_manager.rb +100 -0
  77. data/test/authentication/test_session.rb +93 -0
  78. data/test/common.rb +106 -0
  79. data/test/configs/exact_match +8 -0
  80. data/test/configs/wild_cards +14 -0
  81. data/test/connection/test_channel.rb +452 -0
  82. data/test/connection/test_session.rb +483 -0
  83. data/test/test_all.rb +6 -0
  84. data/test/test_buffer.rb +336 -0
  85. data/test/test_buffered_io.rb +63 -0
  86. data/test/test_config.rb +78 -0
  87. data/test/test_key_factory.rb +67 -0
  88. data/test/transport/hmac/test_md5.rb +34 -0
  89. data/test/transport/hmac/test_md5_96.rb +25 -0
  90. data/test/transport/hmac/test_none.rb +34 -0
  91. data/test/transport/hmac/test_sha1.rb +34 -0
  92. data/test/transport/hmac/test_sha1_96.rb +25 -0
  93. data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +146 -0
  94. data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +92 -0
  95. data/test/transport/test_algorithms.rb +302 -0
  96. data/test/transport/test_cipher_factory.rb +163 -0
  97. data/test/transport/test_hmac.rb +34 -0
  98. data/test/transport/test_identity_cipher.rb +40 -0
  99. data/test/transport/test_packet_stream.rb +433 -0
  100. data/test/transport/test_server_version.rb +55 -0
  101. data/test/transport/test_session.rb +312 -0
  102. data/test/transport/test_state.rb +173 -0
  103. metadata +102 -253
  104. data/ChangeLog +0 -560
  105. data/LICENSE +0 -7
  106. data/NEWS +0 -152
  107. data/README +0 -14
  108. data/bin/rb-keygen +0 -210
  109. data/doc/LICENSE-BSD +0 -27
  110. data/doc/LICENSE-GPL +0 -280
  111. data/doc/LICENSE-RUBY +0 -56
  112. data/doc/manual-html/chapter-1.html +0 -388
  113. data/doc/manual-html/chapter-2.html +0 -552
  114. data/doc/manual-html/chapter-3.html +0 -470
  115. data/doc/manual-html/chapter-4.html +0 -413
  116. data/doc/manual-html/chapter-5.html +0 -525
  117. data/doc/manual-html/chapter-6.html +0 -456
  118. data/doc/manual-html/chapter-7.html +0 -343
  119. data/doc/manual-html/index.html +0 -235
  120. data/doc/manual-html/stylesheets/manual.css +0 -270
  121. data/doc/manual-html/stylesheets/ruby.css +0 -17
  122. data/doc/manual/chapter.erb +0 -38
  123. data/doc/manual/example.erb +0 -18
  124. data/doc/manual/index.erb +0 -29
  125. data/doc/manual/manual.rb +0 -311
  126. data/doc/manual/manual.yml +0 -73
  127. data/doc/manual/page.erb +0 -87
  128. data/doc/manual/parts/0000.txt +0 -5
  129. data/doc/manual/parts/0001.txt +0 -3
  130. data/doc/manual/parts/0002.txt +0 -40
  131. data/doc/manual/parts/0003.txt +0 -6
  132. data/doc/manual/parts/0004.txt +0 -7
  133. data/doc/manual/parts/0005.txt +0 -1
  134. data/doc/manual/parts/0006.txt +0 -49
  135. data/doc/manual/parts/0007.txt +0 -67
  136. data/doc/manual/parts/0008.txt +0 -43
  137. data/doc/manual/parts/0009.txt +0 -14
  138. data/doc/manual/parts/0010.txt +0 -7
  139. data/doc/manual/parts/0011.txt +0 -14
  140. data/doc/manual/parts/0012.txt +0 -3
  141. data/doc/manual/parts/0013.txt +0 -20
  142. data/doc/manual/parts/0014.txt +0 -32
  143. data/doc/manual/parts/0015.txt +0 -14
  144. data/doc/manual/parts/0016.txt +0 -28
  145. data/doc/manual/parts/0017.txt +0 -50
  146. data/doc/manual/parts/0018.txt +0 -35
  147. data/doc/manual/parts/0019.txt +0 -7
  148. data/doc/manual/parts/0020.txt +0 -72
  149. data/doc/manual/parts/0021.txt +0 -50
  150. data/doc/manual/parts/0022.txt +0 -42
  151. data/doc/manual/parts/0023.txt +0 -51
  152. data/doc/manual/parts/0024.txt +0 -18
  153. data/doc/manual/parts/0025.txt +0 -18
  154. data/doc/manual/parts/0026.txt +0 -15
  155. data/doc/manual/parts/0027.txt +0 -37
  156. data/doc/manual/parts/0028.txt +0 -16
  157. data/doc/manual/parts/0029.txt +0 -1
  158. data/doc/manual/parts/0030.txt +0 -52
  159. data/doc/manual/parts/0031.txt +0 -25
  160. data/doc/manual/stylesheets/manual.css +0 -270
  161. data/doc/manual/stylesheets/ruby.css +0 -17
  162. data/doc/manual/tutorial.erb +0 -30
  163. data/examples/auth-forward.rb +0 -41
  164. data/examples/channel-demo.rb +0 -81
  165. data/examples/port-forward.rb +0 -51
  166. data/examples/process-demo.rb +0 -91
  167. data/examples/remote-net-port-forward.rb +0 -45
  168. data/examples/remote-port-forward.rb +0 -80
  169. data/examples/shell-demo.rb +0 -46
  170. data/examples/ssh-client.rb +0 -67
  171. data/examples/sync-shell-demo.rb +0 -69
  172. data/examples/tail-demo.rb +0 -49
  173. data/lib/net/ssh/connection/driver.rb +0 -446
  174. data/lib/net/ssh/connection/services.rb +0 -72
  175. data/lib/net/ssh/host-key-verifier.rb +0 -52
  176. data/lib/net/ssh/known-hosts.rb +0 -96
  177. data/lib/net/ssh/lenient-host-key-verifier.rb +0 -25
  178. data/lib/net/ssh/null-host-key-verifier.rb +0 -14
  179. data/lib/net/ssh/service/agentforward/driver.rb +0 -78
  180. data/lib/net/ssh/service/agentforward/services.rb +0 -41
  181. data/lib/net/ssh/service/forward/driver.rb +0 -319
  182. data/lib/net/ssh/service/forward/local-network-handler.rb +0 -71
  183. data/lib/net/ssh/service/forward/remote-network-handler.rb +0 -83
  184. data/lib/net/ssh/service/forward/services.rb +0 -76
  185. data/lib/net/ssh/service/process/driver.rb +0 -153
  186. data/lib/net/ssh/service/process/open.rb +0 -193
  187. data/lib/net/ssh/service/process/popen3.rb +0 -178
  188. data/lib/net/ssh/service/process/services.rb +0 -66
  189. data/lib/net/ssh/service/services.rb +0 -60
  190. data/lib/net/ssh/service/shell/driver.rb +0 -86
  191. data/lib/net/ssh/service/shell/services.rb +0 -54
  192. data/lib/net/ssh/service/shell/shell.rb +0 -222
  193. data/lib/net/ssh/service/shell/sync.rb +0 -114
  194. data/lib/net/ssh/session.rb +0 -305
  195. data/lib/net/ssh/transport/algorithm-negotiator.rb +0 -275
  196. data/lib/net/ssh/transport/compress/compressor.rb +0 -53
  197. data/lib/net/ssh/transport/compress/decompressor.rb +0 -53
  198. data/lib/net/ssh/transport/compress/none-compressor.rb +0 -39
  199. data/lib/net/ssh/transport/compress/none-decompressor.rb +0 -39
  200. data/lib/net/ssh/transport/compress/services.rb +0 -68
  201. data/lib/net/ssh/transport/compress/zlib-compressor.rb +0 -60
  202. data/lib/net/ssh/transport/compress/zlib-decompressor.rb +0 -52
  203. data/lib/net/ssh/transport/errors.rb +0 -47
  204. data/lib/net/ssh/transport/identity-cipher.rb +0 -61
  205. data/lib/net/ssh/transport/kex/dh-gex.rb +0 -106
  206. data/lib/net/ssh/transport/kex/dh.rb +0 -249
  207. data/lib/net/ssh/transport/kex/services.rb +0 -62
  208. data/lib/net/ssh/transport/ossl/buffer-factory.rb +0 -52
  209. data/lib/net/ssh/transport/ossl/buffer.rb +0 -87
  210. data/lib/net/ssh/transport/ossl/cipher-factory.rb +0 -98
  211. data/lib/net/ssh/transport/ossl/digest-factory.rb +0 -51
  212. data/lib/net/ssh/transport/ossl/hmac-factory.rb +0 -71
  213. data/lib/net/ssh/transport/ossl/hmac/hmac.rb +0 -62
  214. data/lib/net/ssh/transport/ossl/hmac/md5-96.rb +0 -44
  215. data/lib/net/ssh/transport/ossl/hmac/md5.rb +0 -46
  216. data/lib/net/ssh/transport/ossl/hmac/none.rb +0 -46
  217. data/lib/net/ssh/transport/ossl/hmac/services.rb +0 -68
  218. data/lib/net/ssh/transport/ossl/hmac/sha1-96.rb +0 -44
  219. data/lib/net/ssh/transport/ossl/hmac/sha1.rb +0 -45
  220. data/lib/net/ssh/transport/ossl/key-factory.rb +0 -116
  221. data/lib/net/ssh/transport/ossl/services.rb +0 -149
  222. data/lib/net/ssh/transport/packet-stream.rb +0 -236
  223. data/lib/net/ssh/transport/services.rb +0 -146
  224. data/lib/net/ssh/transport/version-negotiator.rb +0 -73
  225. data/lib/net/ssh/userauth/agent.rb +0 -222
  226. data/lib/net/ssh/userauth/constants.rb +0 -35
  227. data/lib/net/ssh/userauth/driver.rb +0 -183
  228. data/lib/net/ssh/userauth/methods/hostbased.rb +0 -119
  229. data/lib/net/ssh/userauth/methods/keyboard-interactive.rb +0 -104
  230. data/lib/net/ssh/userauth/methods/password.rb +0 -70
  231. data/lib/net/ssh/userauth/methods/publickey.rb +0 -137
  232. data/lib/net/ssh/userauth/methods/services.rb +0 -90
  233. data/lib/net/ssh/userauth/pageant.rb +0 -197
  234. data/lib/net/ssh/userauth/services.rb +0 -141
  235. data/lib/net/ssh/userauth/userkeys.rb +0 -258
  236. data/lib/net/ssh/util/buffer.rb +0 -274
  237. data/lib/net/ssh/util/prompter.rb +0 -73
  238. data/test/ALL-TESTS.rb +0 -18
  239. data/test/connection/tc_channel.rb +0 -136
  240. data/test/connection/tc_driver.rb +0 -287
  241. data/test/connection/tc_integration.rb +0 -87
  242. data/test/proxy/tc_http.rb +0 -209
  243. data/test/proxy/tc_socks4.rb +0 -148
  244. data/test/proxy/tc_socks5.rb +0 -214
  245. data/test/service/agentforward/tc_driver.rb +0 -138
  246. data/test/service/forward/tc_driver.rb +0 -289
  247. data/test/service/forward/tc_local_network_handler.rb +0 -123
  248. data/test/service/forward/tc_remote_network_handler.rb +0 -111
  249. data/test/service/process/tc_driver.rb +0 -79
  250. data/test/service/process/tc_integration.rb +0 -119
  251. data/test/service/process/tc_open.rb +0 -179
  252. data/test/service/process/tc_popen3.rb +0 -164
  253. data/test/tc_integration.rb +0 -80
  254. data/test/transport/compress/tc_none_compress.rb +0 -41
  255. data/test/transport/compress/tc_none_decompress.rb +0 -45
  256. data/test/transport/compress/tc_zlib_compress.rb +0 -61
  257. data/test/transport/compress/tc_zlib_decompress.rb +0 -48
  258. data/test/transport/kex/tc_dh.rb +0 -312
  259. data/test/transport/kex/tc_dh_gex.rb +0 -71
  260. data/test/transport/ossl/fixtures/dsa-encrypted +0 -15
  261. data/test/transport/ossl/fixtures/dsa-encrypted-bad +0 -15
  262. data/test/transport/ossl/fixtures/dsa-unencrypted +0 -12
  263. data/test/transport/ossl/fixtures/dsa-unencrypted-bad +0 -12
  264. data/test/transport/ossl/fixtures/dsa-unencrypted.pub +0 -1
  265. data/test/transport/ossl/fixtures/not-a-private-key +0 -4
  266. data/test/transport/ossl/fixtures/not-supported +0 -2
  267. data/test/transport/ossl/fixtures/rsa-encrypted +0 -18
  268. data/test/transport/ossl/fixtures/rsa-encrypted-bad +0 -18
  269. data/test/transport/ossl/fixtures/rsa-unencrypted +0 -15
  270. data/test/transport/ossl/fixtures/rsa-unencrypted-bad +0 -15
  271. data/test/transport/ossl/fixtures/rsa-unencrypted.pub +0 -1
  272. data/test/transport/ossl/hmac/tc_hmac.rb +0 -58
  273. data/test/transport/ossl/hmac/tc_md5.rb +0 -50
  274. data/test/transport/ossl/hmac/tc_md5_96.rb +0 -50
  275. data/test/transport/ossl/hmac/tc_none.rb +0 -50
  276. data/test/transport/ossl/hmac/tc_sha1.rb +0 -50
  277. data/test/transport/ossl/hmac/tc_sha1_96.rb +0 -50
  278. data/test/transport/ossl/tc_buffer.rb +0 -97
  279. data/test/transport/ossl/tc_buffer_factory.rb +0 -67
  280. data/test/transport/ossl/tc_cipher_factory.rb +0 -84
  281. data/test/transport/ossl/tc_digest_factory.rb +0 -39
  282. data/test/transport/ossl/tc_hmac_factory.rb +0 -72
  283. data/test/transport/ossl/tc_key_factory.rb +0 -199
  284. data/test/transport/tc_algorithm_negotiator.rb +0 -170
  285. data/test/transport/tc_identity_cipher.rb +0 -52
  286. data/test/transport/tc_integration.rb +0 -115
  287. data/test/transport/tc_packet_stream.rb +0 -184
  288. data/test/transport/tc_session.rb +0 -296
  289. data/test/transport/tc_version_negotiator.rb +0 -86
  290. data/test/userauth/methods/tc_hostbased.rb +0 -136
  291. data/test/userauth/methods/tc_password.rb +0 -89
  292. data/test/userauth/methods/tc_publickey.rb +0 -167
  293. data/test/userauth/tc_agent.rb +0 -223
  294. data/test/userauth/tc_driver.rb +0 -190
  295. data/test/userauth/tc_integration.rb +0 -97
  296. data/test/userauth/tc_userkeys.rb +0 -265
  297. data/test/util/tc_buffer.rb +0 -217
@@ -0,0 +1,81 @@
1
+ require 'net/ssh/connection/constants'
2
+ require 'net/ssh/transport/constants'
3
+
4
+ module Net; module SSH; module Test
5
+
6
+ # This is an abstract class, not to be instantiated directly, subclassed by
7
+ # Net::SSH::Test::LocalPacket and Net::SSH::Test::RemotePacket. It implements
8
+ # functionality common to those subclasses.
9
+ #
10
+ # These packets are not true packets, in that they don't represent what was
11
+ # actually sent between the hosst; rather, they represent what was expected
12
+ # to be sent, as dictated by the script (Net::SSH::Test::Script). Thus,
13
+ # though they are defined with data elements, these data elements are used
14
+ # to either validate data that was sent by the local host (Net::SSH::Test::LocalPacket)
15
+ # or to mimic the sending of data by the remote host (Net::SSH::Test::RemotePacket).
16
+ class Packet
17
+ include Net::SSH::Transport::Constants
18
+ include Net::SSH::Connection::Constants
19
+
20
+ # Ceate a new packet of the given +type+, and with +args+ being a list of
21
+ # data elements in the order expected for packets of the given +type+
22
+ # (see #types).
23
+ def initialize(type, *args)
24
+ @type = self.class.const_get(type.to_s.upcase)
25
+ @data = args
26
+ end
27
+
28
+ # The default for +remote?+ is false. Subclasses should override as necessary.
29
+ def remote?
30
+ false
31
+ end
32
+
33
+ # The default for +local?+ is false. Subclasses should override as necessary.
34
+ def local?
35
+ false
36
+ end
37
+
38
+ # Instantiates the packets data elements. When the packet was first defined,
39
+ # some elements may not have been fully realized, and were described as
40
+ # Proc objects rather than atomic types. This invokes those Proc objects
41
+ # and replaces them with their returned values. This allows for values
42
+ # like Net::SSH::Test::Channel#remote_id to be used in scripts before
43
+ # the remote_id is known (since it is only known after a channel has been
44
+ # confirmed open).
45
+ def instantiate!
46
+ @data.map! { |i| i.respond_to?(:call) ? i.call : i }
47
+ end
48
+
49
+ # Returns an array of symbols describing the data elements for packets of
50
+ # the same type as this packet. These types are used to either validate
51
+ # sent packets (Net::SSH::Test::LocalPacket) or build received packets
52
+ # (Net::SSH::Test::RemotePacket).
53
+ #
54
+ # Not all packet types are defined here. As new packet types are required
55
+ # (e.g., a unit test needs to test that the remote host sent a packet that
56
+ # is not implemented here), the description of that packet should be
57
+ # added. Unsupported packet types will otherwise raise an exception.
58
+ def types
59
+ @types ||= case @type
60
+ when KEXINIT then
61
+ [:long, :long, :long, :long,
62
+ :string, :string, :string, :string, :string, :string, :string, :string, :string, :string,
63
+ :bool]
64
+ when NEWKEYS then []
65
+ when CHANNEL_OPEN then [:string, :long, :long, :long]
66
+ when CHANNEL_OPEN_CONFIRMATION then [:long, :long, :long, :long]
67
+ when CHANNEL_DATA then [:long, :string]
68
+ when CHANNEL_EOF, CHANNEL_CLOSE, CHANNEL_SUCCESS, CHANNEL_FAILURE then [:long]
69
+ when CHANNEL_REQUEST
70
+ parts = [:long, :string, :bool]
71
+ case @data[1]
72
+ when "exec", "subsystem" then parts << :string
73
+ when "exit-status" then parts << :long
74
+ else raise "don't know what to do about #{@data[1]} channel request"
75
+ end
76
+ else raise "don't know how to parse packet type #{@type}"
77
+ end
78
+ end
79
+ end
80
+
81
+ end; end; end
@@ -0,0 +1,38 @@
1
+ require 'net/ssh/buffer'
2
+ require 'net/ssh/test/packet'
3
+
4
+ module Net; module SSH; module Test
5
+
6
+ # This is a specialization of Net::SSH::Test::Packet for representing mock
7
+ # packets that are received by the local (client) host. These are created
8
+ # automatically by Net::SSH::Test::Script and Net::SSH::Test::Channel by any
9
+ # of the gets_* methods.
10
+ class RemotePacket < Packet
11
+ # Returns +true+; this is a remote packet.
12
+ def remote?
13
+ true
14
+ end
15
+
16
+ # The #process method should only be called on Net::SSH::Test::LocalPacket
17
+ # packets; if it is attempted on a remote packet, then it is an expectation
18
+ # mismatch (a remote packet was received when a local packet was expected
19
+ # to be sent). This will happen when either your test script
20
+ # (Net::SSH::Test::Script) or your program are wrong.
21
+ def process(packet)
22
+ raise "received packet type #{packet.read_byte} and was not expecting any packet"
23
+ end
24
+
25
+ # Returns this remote packet as a string, suitable for parsing by
26
+ # Net::SSH::Transport::PacketStream and friends. When a remote packet is
27
+ # received, this method is called and the result concatenated onto the
28
+ # input buffer for the packet stream.
29
+ def to_s
30
+ @to_s ||= begin
31
+ instantiate!
32
+ string = Net::SSH::Buffer.from(:byte, @type, *types.zip(@data).flatten).to_s
33
+ [string.length, string].pack("NA*")
34
+ end
35
+ end
36
+ end
37
+
38
+ end; end; end
@@ -0,0 +1,157 @@
1
+ require 'net/ssh/test/channel'
2
+ require 'net/ssh/test/local_packet'
3
+ require 'net/ssh/test/remote_packet'
4
+
5
+ module Net; module SSH; module Test
6
+
7
+ # Represents a sequence of scripted events that identify the behavior that
8
+ # a test expects. Methods named "sends_*" create events for packets being
9
+ # sent from the local to the remote host, and methods named "gets_*" create
10
+ # events for packets being received by the local from the remote host.
11
+ #
12
+ # A reference to a script. is generally obtained in a unit test via the
13
+ # Net::SSH::Test#story helper method:
14
+ #
15
+ # story do |script|
16
+ # channel = script.opens_channel
17
+ # ...
18
+ # end
19
+ class Script
20
+ # The list of scripted events. These will be Net::SSH::Test::LocalPacket
21
+ # and Net::SSH::Test::RemotePacket instances.
22
+ attr_reader :events
23
+
24
+ # Create a new, empty script.
25
+ def initialize
26
+ @events = []
27
+ end
28
+
29
+ # Scripts the opening of a channel by adding a local packet sending the
30
+ # channel open request, and if +confirm+ is true (the default), also
31
+ # adding a remote packet confirming the new channel.
32
+ #
33
+ # A new Net::SSH::Test::Channel instance is returned, which can be used
34
+ # to script additional channel operations.
35
+ def opens_channel(confirm=true)
36
+ channel = Channel.new(self)
37
+ channel.remote_id = 5555
38
+
39
+ events << LocalPacket.new(:channel_open) { |p| channel.local_id = p[:remote_id] }
40
+
41
+ if confirm
42
+ events << RemotePacket.new(:channel_open_confirmation, channel.local_id, channel.remote_id, 0x20000, 0x10000)
43
+ end
44
+
45
+ channel
46
+ end
47
+
48
+ # A convenience method for adding an arbitrary local packet to the events
49
+ # list.
50
+ def sends(type, *args, &block)
51
+ events << LocalPacket.new(type, *args, &block)
52
+ end
53
+
54
+ # A convenience method for adding an arbitrary remote packet to the events
55
+ # list.
56
+ def gets(type, *args)
57
+ events << RemotePacket.new(type, *args)
58
+ end
59
+
60
+ # Scripts the sending of a new channel request packet to the remote host.
61
+ # +channel+ should be an instance of Net::SSH::Test::Channel. +request+
62
+ # is a string naming the request type to send, +reply+ is a boolean
63
+ # indicating whether a response to this packet is required , and +data+
64
+ # is any additional request-specific data that this packet should send.
65
+ # +success+ indicates whether the response (if one is required) should be
66
+ # success or failure.
67
+ #
68
+ # If a reply is desired, a remote packet will also be queued, :channel_success
69
+ # if +success+ is true, or :channel_failure if +success+ is false.
70
+ #
71
+ # This will typically be called via Net::SSH::Test::Channel#sends_exec or
72
+ # Net::SSH::Test::Channel#sends_subsystem.
73
+ def sends_channel_request(channel, request, reply, data, success=true)
74
+ events << LocalPacket.new(:channel_request, channel.remote_id, request, reply, data)
75
+ if reply
76
+ if success
77
+ events << RemotePacket.new(:channel_success, channel.local_id)
78
+ else
79
+ events << RemotePacket.new(:channel_failure, channel.local_id)
80
+ end
81
+ end
82
+ end
83
+
84
+ # Scripts the sending of a channel data packet. +channel+ must be a
85
+ # Net::SSH::Test::Channel object, and +data+ is the (string) data to
86
+ # expect will be sent.
87
+ #
88
+ # This will typically be called via Net::SSH::Test::Channel#sends_data.
89
+ def sends_channel_data(channel, data)
90
+ events << LocalPacket.new(:channel_data, channel.remote_id, data)
91
+ end
92
+
93
+ # Scripts the sending of a channel EOF packet from the given
94
+ # Net::SSH::Test::Channel +channel+. This will typically be called via
95
+ # Net::SSH::Test::Channel#sends_eof.
96
+ def sends_channel_eof(channel)
97
+ events << LocalPacket.new(:channel_eof, channel.remote_id)
98
+ end
99
+
100
+ # Scripts the sending of a channel close packet from the given
101
+ # Net::SSH::Test::Channel +channel+. This will typically be called via
102
+ # Net::SSH::Test::Channel#sends_close.
103
+ def sends_channel_close(channel)
104
+ events << LocalPacket.new(:channel_close, channel.remote_id)
105
+ end
106
+
107
+ # Scripts the reception of a channel data packet from the remote host by
108
+ # the given Net::SSH::Test::Channel +channel+. This will typically be
109
+ # called via Net::SSH::Test::Channel#gets_data.
110
+ def gets_channel_data(channel, data)
111
+ events << RemotePacket.new(:channel_data, channel.local_id, data)
112
+ end
113
+
114
+ # Scripts the reception of a channel request packet from the remote host by
115
+ # the given Net::SSH::Test::Channel +channel+. This will typically be
116
+ # called via Net::SSH::Test::Channel#gets_exit_status.
117
+ def gets_channel_request(channel, request, reply, data)
118
+ events << RemotePacket.new(:channel_request, channel.local_id, request, reply, data)
119
+ end
120
+
121
+ # Scripts the reception of a channel EOF packet from the remote host by
122
+ # the given Net::SSH::Test::Channel +channel+. This will typically be
123
+ # called via Net::SSH::Test::Channel#gets_eof.
124
+ def gets_channel_eof(channel)
125
+ events << RemotePacket.new(:channel_eof, channel.local_id)
126
+ end
127
+
128
+ # Scripts the reception of a channel close packet from the remote host by
129
+ # the given Net::SSH::Test::Channel +channel+. This will typically be
130
+ # called via Net::SSH::Test::Channel#gets_close.
131
+ def gets_channel_close(channel)
132
+ events << RemotePacket.new(:channel_close, channel.local_id)
133
+ end
134
+
135
+ # By default, removes the next event in the list and returns it. However,
136
+ # this can also be used to non-destructively peek at the next event in the
137
+ # list, by passing :first as the argument.
138
+ #
139
+ # # remove the next event and return it
140
+ # event = script.next
141
+ #
142
+ # # peek at the next event
143
+ # event = script.next(:first)
144
+ def next(mode=:shift)
145
+ events.send(mode)
146
+ end
147
+
148
+ # Compare the given packet against the next event in the list. If there is
149
+ # no next event, an exception will be raised. This is called by
150
+ # Net::SSH::Test::Extensions::PacketStream#test_enqueue_packet.
151
+ def process(packet)
152
+ event = events.shift or raise "end of script reached, but got a packet type #{packet.read_byte}"
153
+ event.process(packet)
154
+ end
155
+ end
156
+
157
+ end; end; end
@@ -0,0 +1,59 @@
1
+ require 'socket'
2
+ require 'stringio'
3
+ require 'net/ssh/test/extensions'
4
+ require 'net/ssh/test/script'
5
+
6
+ module Net; module SSH; module Test
7
+
8
+ # A mock socket implementation for use in testing. It implements the minimum
9
+ # necessary interface for interacting with the rest of the Net::SSH::Test
10
+ # system.
11
+ class Socket < StringIO
12
+ attr_reader :host, :port
13
+
14
+ # The Net::SSH::Test::Script object in use by this socket. This is the
15
+ # canonical script instance that should be used for any test depending on
16
+ # this socket instance.
17
+ attr_reader :script
18
+
19
+ # Create a new test socket. This will also instantiate a new Net::SSH::Test::Script
20
+ # and seed it with the necessary events to power the initialization of the
21
+ # connection.
22
+ def initialize
23
+ extend(Net::SSH::Transport::PacketStream)
24
+ super "SSH-2.0-Test\r\n"
25
+
26
+ @script = Script.new
27
+
28
+ script.gets(:kexinit, 1, 2, 3, 4, "test", "ssh-rsa", "none", "none", "none", "none", "none", "none", "", "", false)
29
+ script.sends(:kexinit)
30
+ script.sends(:newkeys)
31
+ script.gets(:newkeys)
32
+ end
33
+
34
+ # This doesn't actually do anything, since we don't really care what gets
35
+ # written.
36
+ def write(data)
37
+ # black hole, because we don't actually care about what gets written
38
+ end
39
+
40
+ # Allows the socket to also mimic a socket factory, simply returning
41
+ # +self+.
42
+ def open(host, port)
43
+ @host, @port = host, port
44
+ self
45
+ end
46
+
47
+ # Returns a sockaddr struct for the port and host that were used when the
48
+ # socket was instantiated.
49
+ def getpeername
50
+ ::Socket.sockaddr_in(port, host)
51
+ end
52
+
53
+ # Alias to #read, but never returns nil (returns an empty string instead).
54
+ def recv(n)
55
+ read(n) || ""
56
+ end
57
+ end
58
+
59
+ end; end; end
@@ -0,0 +1,384 @@
1
+ require 'net/ssh/buffer'
2
+ require 'net/ssh/known_hosts'
3
+ require 'net/ssh/loggable'
4
+ require 'net/ssh/transport/cipher_factory'
5
+ require 'net/ssh/transport/constants'
6
+ require 'net/ssh/transport/hmac'
7
+ require 'net/ssh/transport/kex'
8
+ require 'net/ssh/transport/server_version'
9
+
10
+ module Net; module SSH; module Transport
11
+
12
+ # Implements the higher-level logic behind an SSH key-exchange. It handles
13
+ # both the initial exchange, as well as subsequent re-exchanges (as needed).
14
+ # It also encapsulates the negotiation of the algorithms, and provides a
15
+ # single point of access to the negotiated algorithms.
16
+ #
17
+ # You will never instantiate or reference this directly. It is used
18
+ # internally by the transport layer.
19
+ class Algorithms
20
+ include Constants, Loggable
21
+
22
+ # Define the default algorithms, in order of preference, supported by
23
+ # Net::SSH.
24
+ ALGORITHMS = {
25
+ :host_key => %w(ssh-rsa ssh-dss),
26
+ :kex => %w(diffie-hellman-group-exchange-sha1
27
+ diffie-hellman-group1-sha1),
28
+ :encryption => %w(aes128-cbc 3des-cbc blowfish-cbc cast128-cbc
29
+ aes192-cbc aes256-cbc rijndael-cbc@lysator.liu.se
30
+ idea-cbc none),
31
+ :hmac => %w(hmac-sha1 hmac-md5 hmac-sha1-96 hmac-md5-96 none),
32
+ :compression => %w(none zlib@openssh.com zlib),
33
+ :language => %w()
34
+ }
35
+
36
+ # The underlying transport layer session that supports this object
37
+ attr_reader :session
38
+
39
+ # The hash of options used to initialize this object
40
+ attr_reader :options
41
+
42
+ # The kex algorithm to use settled on between the client and server.
43
+ attr_reader :kex
44
+
45
+ # The type of host key that will be used for this session.
46
+ attr_reader :host_key
47
+
48
+ # The type of the cipher to use to encrypt packets sent from the client to
49
+ # the server.
50
+ attr_reader :encryption_client
51
+
52
+ # The type of the cipher to use to decrypt packets arriving from the server.
53
+ attr_reader :encryption_server
54
+
55
+ # The type of HMAC to use to sign packets sent by the client.
56
+ attr_reader :hmac_client
57
+
58
+ # The type of HMAC to use to validate packets arriving from the server.
59
+ attr_reader :hmac_server
60
+
61
+ # The type of compression to use to compress packets being sent by the client.
62
+ attr_reader :compression_client
63
+
64
+ # The type of compression to use to decompress packets arriving from the server.
65
+ attr_reader :compression_server
66
+
67
+ # The language that will be used in messages sent by the client.
68
+ attr_reader :language_client
69
+
70
+ # The language that will be used in messages sent from the server.
71
+ attr_reader :language_server
72
+
73
+ # The hash of algorithms preferred by the client, which will be told to
74
+ # the server during algorithm negotiation.
75
+ attr_reader :algorithms
76
+
77
+ # The session-id for this session, as decided during the initial key exchange.
78
+ attr_reader :session_id
79
+
80
+ # Returns true if the given packet can be processed during a key-exchange.
81
+ def self.allowed_packet?(packet)
82
+ ( 1.. 4).include?(packet.type) ||
83
+ ( 6..19).include?(packet.type) ||
84
+ (21..49).include?(packet.type)
85
+ end
86
+
87
+ # Instantiates a new Algorithms object, and prepares the hash of preferred
88
+ # algorithms based on the options parameter and the ALGORITHMS constant.
89
+ def initialize(session, options={})
90
+ @session = session
91
+ @logger = session.logger
92
+ @options = options
93
+ @algorithms = {}
94
+ @pending = @initialized = false
95
+ @client_packet = @server_packet = nil
96
+ prepare_preferred_algorithms!
97
+ end
98
+
99
+ # Request a rekey operation. This will return immediately, and does not
100
+ # actually perform the rekey operation. It does cause the session to change
101
+ # state, however--until the key exchange finishes, no new packets will be
102
+ # processed.
103
+ def rekey!
104
+ @client_packet = @server_packet = nil
105
+ @initialized = false
106
+ send_kexinit
107
+ end
108
+
109
+ # Called by the transport layer when a KEXINIT packet is recieved, indicating
110
+ # that the server wants to exchange keys. This can be spontaneous, or it
111
+ # can be in response to a client-initiated rekey request (see #rekey!). Either
112
+ # way, this will block until the key exchange completes.
113
+ def accept_kexinit(packet)
114
+ info { "got KEXINIT from server" }
115
+ @server_data = parse_server_algorithm_packet(packet)
116
+ @server_packet = @server_data[:raw]
117
+ if !pending?
118
+ send_kexinit
119
+ else
120
+ proceed!
121
+ end
122
+ end
123
+
124
+ # A convenience method for accessing the list of preferred types for a
125
+ # specific algorithm (see #algorithms).
126
+ def [](key)
127
+ algorithms[key]
128
+ end
129
+
130
+ # Returns +true+ if a key-exchange is pending. This will be true from the
131
+ # moment either the client or server requests the key exchange, until the
132
+ # exchange completes. While an exchange is pending, only a limited number
133
+ # of packets are allowed, so event processing essentially stops during this
134
+ # period.
135
+ def pending?
136
+ @pending
137
+ end
138
+
139
+ # Returns true if no exchange is pending, and otherwise returns true or
140
+ # false depending on whether the given packet is of a type that is allowed
141
+ # during a key exchange.
142
+ def allow?(packet)
143
+ !pending? || Algorithms.allowed_packet?(packet)
144
+ end
145
+
146
+ # Returns true if the algorithms have been negotiated at all.
147
+ def initialized?
148
+ @initialized
149
+ end
150
+
151
+ private
152
+
153
+ # Sends a KEXINIT packet to the server. If a server KEXINIT has already
154
+ # been received, this will then invoke #proceed! to proceed with the key
155
+ # exchange, otherwise it returns immediately (but sets the object to the
156
+ # pending state).
157
+ def send_kexinit
158
+ info { "sending KEXINIT" }
159
+ @pending = true
160
+ packet = build_client_algorithm_packet
161
+ @client_packet = packet.to_s
162
+ session.send_message(packet)
163
+ proceed! if @server_packet
164
+ end
165
+
166
+ # After both client and server have sent their KEXINIT packets, this
167
+ # will do the algorithm negotiation and key exchange. Once both finish,
168
+ # the object leaves the pending state and the method returns.
169
+ def proceed!
170
+ info { "negotiating algorithms" }
171
+ negotiate_algorithms
172
+ exchange_keys
173
+ @pending = false
174
+ end
175
+
176
+ # Prepares the list of preferred algorithms, based on the options hash
177
+ # that was given when the object was constructed, and the ALGORITHMS
178
+ # constant. Also, when determining the host_key type to use, the known
179
+ # hosts files are examined to see if the host has ever sent a host_key
180
+ # before, and if so, that key type is used as the preferred type for
181
+ # communicating with this server.
182
+ def prepare_preferred_algorithms!
183
+ options[:compression] = %w(zlib@openssh.com zlib) if options[:compression] == true
184
+
185
+ ALGORITHMS.each do |algorithm, list|
186
+ algorithms[algorithm] = list.dup
187
+
188
+ # apply the preferred algorithm order, if any
189
+ if options[algorithm]
190
+ algorithms[algorithm] = Array(options[algorithm]).compact.uniq
191
+ invalid = algorithms[algorithm].detect { |name| !ALGORITHMS[algorithm].include?(name) }
192
+ raise NotImplementedError, "unsupported #{algorithm} algorithm: `#{invalid}'" if invalid
193
+
194
+ # make sure all of our supported algorithms are tacked onto the
195
+ # end, so that if the user tries to give a list of which none are
196
+ # supported, we can still proceed.
197
+ list.each { |name| algorithms[algorithm] << name unless algorithms[algorithm].include?(name) }
198
+ end
199
+ end
200
+
201
+ # for convention, make sure our list has the same keys as the server
202
+ # list
203
+
204
+ algorithms[:encryption_client ] = algorithms[:encryption_server ] = algorithms[:encryption]
205
+ algorithms[:hmac_client ] = algorithms[:hmac_server ] = algorithms[:hmac]
206
+ algorithms[:compression_client] = algorithms[:compression_server] = algorithms[:compression]
207
+ algorithms[:language_client ] = algorithms[:language_server ] = algorithms[:language]
208
+
209
+ if !options.key?(:host_key)
210
+ # make sure the host keys are specified in preference order, where any
211
+ # existing known key for the host has preference.
212
+
213
+ existing_keys = KnownHosts.search_for(options[:host_key_alias] || session.host_as_string, options)
214
+ host_keys = existing_keys.map { |key| key.ssh_type }.uniq
215
+ algorithms[:host_key].each do |name|
216
+ host_keys << name unless host_keys.include?(name)
217
+ end
218
+ algorithms[:host_key] = host_keys
219
+ end
220
+ end
221
+
222
+ # Parses a KEXINIT packet from the server.
223
+ def parse_server_algorithm_packet(packet)
224
+ data = { :raw => packet.content }
225
+
226
+ packet.read(16) # skip the cookie value
227
+
228
+ data[:kex] = packet.read_string.split(/,/)
229
+ data[:host_key] = packet.read_string.split(/,/)
230
+ data[:encryption_client] = packet.read_string.split(/,/)
231
+ data[:encryption_server] = packet.read_string.split(/,/)
232
+ data[:hmac_client] = packet.read_string.split(/,/)
233
+ data[:hmac_server] = packet.read_string.split(/,/)
234
+ data[:compression_client] = packet.read_string.split(/,/)
235
+ data[:compression_server] = packet.read_string.split(/,/)
236
+ data[:language_client] = packet.read_string.split(/,/)
237
+ data[:language_server] = packet.read_string.split(/,/)
238
+
239
+ # TODO: if first_kex_packet_follows, we need to try to skip the
240
+ # actual kexinit stuff and try to guess what the server is doing...
241
+ # need to read more about this scenario.
242
+ first_kex_packet_follows = packet.read_bool
243
+
244
+ return data
245
+ end
246
+
247
+ # Given the #algorithms map of preferred algorithm types, this constructs
248
+ # a KEXINIT packet to send to the server. It does not actually send it,
249
+ # it simply builds the packet and returns it.
250
+ def build_client_algorithm_packet
251
+ kex = algorithms[:kex ].join(",")
252
+ host_key = algorithms[:host_key ].join(",")
253
+ encryption = algorithms[:encryption ].join(",")
254
+ hmac = algorithms[:hmac ].join(",")
255
+ compression = algorithms[:compression].join(",")
256
+ language = algorithms[:language ].join(",")
257
+
258
+ Net::SSH::Buffer.from(:byte, KEXINIT,
259
+ :long, [rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF)],
260
+ :string, [kex, host_key, encryption, encryption, hmac, hmac],
261
+ :string, [compression, compression, language, language],
262
+ :bool, false, :long, 0)
263
+ end
264
+
265
+ # Given the parsed server KEX packet, and the client's preferred algorithm
266
+ # lists in #algorithms, determine which preferred algorithms each has
267
+ # in common and set those as the selected algorithms. If, for any algorithm,
268
+ # no type can be settled on, an exception is raised.
269
+ def negotiate_algorithms
270
+ @kex = negotiate(:kex)
271
+ @host_key = negotiate(:host_key)
272
+ @encryption_client = negotiate(:encryption_client)
273
+ @encryption_server = negotiate(:encryption_server)
274
+ @hmac_client = negotiate(:hmac_client)
275
+ @hmac_server = negotiate(:hmac_server)
276
+ @compression_client = negotiate(:compression_client)
277
+ @compression_server = negotiate(:compression_server)
278
+ @language_client = negotiate(:language_client) rescue ""
279
+ @language_server = negotiate(:language_server) rescue ""
280
+
281
+ debug do
282
+ "negotiated:\n" +
283
+ [:kex, :host_key, :encryption_server, :encryption_client, :hmac_client, :hmac_server, :compression_client, :compression_server, :language_client, :language_server].map do |key|
284
+ "* #{key}: #{instance_variable_get("@#{key}")}"
285
+ end.join("\n")
286
+ end
287
+ end
288
+
289
+ # Negotiates a single algorithm based on the preferences reported by the
290
+ # server and those set by the client. This is called by
291
+ # #negotiate_algorithms.
292
+ def negotiate(algorithm)
293
+ match = self[algorithm].find { |item| @server_data[algorithm].include?(item) }
294
+
295
+ if match.nil?
296
+ raise Net::SSH::Exception, "could not settle on #{algorithm} algorithm"
297
+ end
298
+
299
+ return match
300
+ end
301
+
302
+ # Considers the sizes of the keys and block-sizes for the selected ciphers,
303
+ # and the lengths of the hmacs, and returns the largest as the byte requirement
304
+ # for the key-exchange algorithm.
305
+ def kex_byte_requirement
306
+ sizes = [8] # require at least 8 bytes
307
+
308
+ sizes.concat(CipherFactory.get_lengths(encryption_client))
309
+ sizes.concat(CipherFactory.get_lengths(encryption_server))
310
+
311
+ sizes << HMAC.key_length(hmac_client)
312
+ sizes << HMAC.key_length(hmac_server)
313
+
314
+ sizes.max
315
+ end
316
+
317
+ # Instantiates one of the Transport::Kex classes (based on the negotiated
318
+ # kex algorithm), and uses it to exchange keys. Then, the ciphers and
319
+ # HMACs are initialized and fed to the transport layer, to be used in
320
+ # further communication with the server.
321
+ def exchange_keys
322
+ debug { "exchanging keys" }
323
+
324
+ algorithm = Kex::MAP[kex].new(self, session,
325
+ :client_version_string => Net::SSH::Transport::ServerVersion::PROTO_VERSION,
326
+ :server_version_string => session.server_version.version,
327
+ :server_algorithm_packet => @server_packet,
328
+ :client_algorithm_packet => @client_packet,
329
+ :need_bytes => kex_byte_requirement,
330
+ :logger => logger)
331
+ result = algorithm.exchange_keys
332
+
333
+ secret = result[:shared_secret].to_ssh
334
+ hash = result[:session_id]
335
+ digester = result[:hashing_algorithm]
336
+
337
+ @session_id ||= hash
338
+
339
+ key = Proc.new { |salt| digester.digest(secret + hash + salt + @session_id) }
340
+
341
+ iv_client = key["A"]
342
+ iv_server = key["B"]
343
+ key_client = key["C"]
344
+ key_server = key["D"]
345
+ mac_key_client = key["E"]
346
+ mac_key_server = key["F"]
347
+
348
+ parameters = { :iv => iv_client, :key => key_client, :shared => secret,
349
+ :hash => hash, :digester => digester }
350
+
351
+ cipher_client = CipherFactory.get(encryption_client, parameters.merge(:encrypt => true))
352
+ cipher_server = CipherFactory.get(encryption_server, parameters.merge(:iv => iv_server, :key => key_server, :decrypt => true))
353
+
354
+ mac_client = HMAC.get(hmac_client, mac_key_client)
355
+ mac_server = HMAC.get(hmac_server, mac_key_server)
356
+
357
+ session.configure_client :cipher => cipher_client, :hmac => mac_client,
358
+ :compression => normalize_compression_name(compression_client),
359
+ :compression_level => options[:compression_level],
360
+ :rekey_limit => options[:rekey_limit],
361
+ :max_packets => options[:rekey_packet_limit],
362
+ :max_blocks => options[:rekey_blocks_limit]
363
+
364
+ session.configure_server :cipher => cipher_server, :hmac => mac_server,
365
+ :compression => normalize_compression_name(compression_server),
366
+ :rekey_limit => options[:rekey_limit],
367
+ :max_packets => options[:rekey_packet_limit],
368
+ :max_blocks => options[:rekey_blocks_limit]
369
+
370
+ @initialized = true
371
+ end
372
+
373
+ # Given the SSH name for some compression algorithm, return a normalized
374
+ # name as a symbol.
375
+ def normalize_compression_name(name)
376
+ case name
377
+ when "none" then false
378
+ when "zlib" then :standard
379
+ when "zlib@openssh.com" then :delayed
380
+ else raise ArgumentError, "unknown compression type `#{name}'"
381
+ end
382
+ end
383
+ end
384
+ end; end; end