net-ssh 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. data/doc/LICENSE-BSD +27 -0
  2. data/doc/LICENSE-GPL +280 -0
  3. data/doc/LICENSE-RUBY +56 -0
  4. data/doc/README +13 -0
  5. data/doc/manual-html/chapter-1.html +333 -0
  6. data/doc/manual-html/chapter-2.html +455 -0
  7. data/doc/manual-html/chapter-3.html +413 -0
  8. data/doc/manual-html/chapter-4.html +353 -0
  9. data/doc/manual-html/chapter-5.html +393 -0
  10. data/doc/manual-html/chapter-6.html +296 -0
  11. data/doc/manual-html/index.html +217 -0
  12. data/doc/manual-html/manual.css +192 -0
  13. data/doc/manual/chapter.erb +18 -0
  14. data/doc/manual/example.erb +18 -0
  15. data/doc/manual/index.erb +29 -0
  16. data/doc/manual/manual.css +192 -0
  17. data/doc/manual/manual.rb +240 -0
  18. data/doc/manual/manual.yml +67 -0
  19. data/doc/manual/page.erb +87 -0
  20. data/doc/manual/parts/channels_callbacks.txt +32 -0
  21. data/doc/manual/parts/channels_loop.txt +14 -0
  22. data/doc/manual/parts/channels_open.txt +20 -0
  23. data/doc/manual/parts/channels_operations.txt +15 -0
  24. data/doc/manual/parts/channels_types.txt +3 -0
  25. data/doc/manual/parts/channels_what_are.txt +7 -0
  26. data/doc/manual/parts/exec_channels.txt +28 -0
  27. data/doc/manual/parts/exec_open.txt +51 -0
  28. data/doc/manual/parts/exec_popen3.txt +35 -0
  29. data/doc/manual/parts/forward_direct.txt +37 -0
  30. data/doc/manual/parts/forward_handlers.txt +16 -0
  31. data/doc/manual/parts/forward_intro.txt +18 -0
  32. data/doc/manual/parts/forward_local.txt +18 -0
  33. data/doc/manual/parts/forward_remote.txt +14 -0
  34. data/doc/manual/parts/intro_author.txt +1 -0
  35. data/doc/manual/parts/intro_getting.txt +39 -0
  36. data/doc/manual/parts/intro_license.txt +6 -0
  37. data/doc/manual/parts/intro_support.txt +7 -0
  38. data/doc/manual/parts/intro_what_is.txt +7 -0
  39. data/doc/manual/parts/intro_what_is_not.txt +3 -0
  40. data/doc/manual/parts/proxy_http.txt +52 -0
  41. data/doc/manual/parts/proxy_intro.txt +1 -0
  42. data/doc/manual/parts/proxy_socks.txt +23 -0
  43. data/doc/manual/parts/session_key.txt +66 -0
  44. data/doc/manual/parts/session_options.txt +42 -0
  45. data/doc/manual/parts/session_session.txt +14 -0
  46. data/doc/manual/parts/session_start.txt +49 -0
  47. data/doc/manual/tutorial.erb +30 -0
  48. data/examples/channel-demo.rb +81 -0
  49. data/examples/port-forward.rb +51 -0
  50. data/examples/process-demo.rb +91 -0
  51. data/examples/remote-net-port-forward.rb +45 -0
  52. data/examples/remote-port-forward.rb +80 -0
  53. data/examples/tail-demo.rb +49 -0
  54. data/lib/net/ssh.rb +52 -0
  55. data/lib/net/ssh/connection/channel.rb +411 -0
  56. data/lib/net/ssh/connection/constants.rb +47 -0
  57. data/lib/net/ssh/connection/driver.rb +343 -0
  58. data/lib/net/ssh/connection/services.rb +72 -0
  59. data/lib/net/ssh/connection/term.rb +90 -0
  60. data/lib/net/ssh/errors.rb +27 -0
  61. data/lib/net/ssh/proxy/errors.rb +34 -0
  62. data/lib/net/ssh/proxy/http.rb +126 -0
  63. data/lib/net/ssh/proxy/socks4.rb +83 -0
  64. data/lib/net/ssh/proxy/socks5.rb +160 -0
  65. data/lib/net/ssh/service/forward/driver.rb +319 -0
  66. data/lib/net/ssh/service/forward/local-network-handler.rb +74 -0
  67. data/lib/net/ssh/service/forward/remote-network-handler.rb +81 -0
  68. data/lib/net/ssh/service/forward/services.rb +76 -0
  69. data/lib/net/ssh/service/process/driver.rb +153 -0
  70. data/lib/net/ssh/service/process/open.rb +193 -0
  71. data/lib/net/ssh/service/process/popen3.rb +160 -0
  72. data/lib/net/ssh/service/process/services.rb +66 -0
  73. data/lib/net/ssh/service/services.rb +44 -0
  74. data/lib/net/ssh/session.rb +242 -0
  75. data/lib/net/ssh/transport/algorithm-negotiator.rb +267 -0
  76. data/lib/net/ssh/transport/compress/compressor.rb +53 -0
  77. data/lib/net/ssh/transport/compress/decompressor.rb +53 -0
  78. data/lib/net/ssh/transport/compress/none-compressor.rb +39 -0
  79. data/lib/net/ssh/transport/compress/none-decompressor.rb +39 -0
  80. data/lib/net/ssh/transport/compress/services.rb +68 -0
  81. data/lib/net/ssh/transport/compress/zlib-compressor.rb +60 -0
  82. data/lib/net/ssh/transport/compress/zlib-decompressor.rb +52 -0
  83. data/lib/net/ssh/transport/constants.rb +66 -0
  84. data/lib/net/ssh/transport/errors.rb +47 -0
  85. data/lib/net/ssh/transport/identity-cipher.rb +61 -0
  86. data/lib/net/ssh/transport/kex/dh-gex.rb +106 -0
  87. data/lib/net/ssh/transport/kex/dh.rb +231 -0
  88. data/lib/net/ssh/transport/kex/services.rb +60 -0
  89. data/lib/net/ssh/transport/ossl/buffer-factory.rb +52 -0
  90. data/lib/net/ssh/transport/ossl/buffer.rb +87 -0
  91. data/lib/net/ssh/transport/ossl/cipher-factory.rb +98 -0
  92. data/lib/net/ssh/transport/ossl/digest-factory.rb +51 -0
  93. data/lib/net/ssh/transport/ossl/hmac-factory.rb +71 -0
  94. data/lib/net/ssh/transport/ossl/hmac/hmac.rb +62 -0
  95. data/lib/net/ssh/transport/ossl/hmac/md5-96.rb +44 -0
  96. data/lib/net/ssh/transport/ossl/hmac/md5.rb +46 -0
  97. data/lib/net/ssh/transport/ossl/hmac/none.rb +46 -0
  98. data/lib/net/ssh/transport/ossl/hmac/services.rb +68 -0
  99. data/lib/net/ssh/transport/ossl/hmac/sha1-96.rb +44 -0
  100. data/lib/net/ssh/transport/ossl/hmac/sha1.rb +45 -0
  101. data/lib/net/ssh/transport/ossl/key-factory.rb +113 -0
  102. data/lib/net/ssh/transport/ossl/services.rb +149 -0
  103. data/lib/net/ssh/transport/packet-stream.rb +210 -0
  104. data/lib/net/ssh/transport/services.rb +146 -0
  105. data/lib/net/ssh/transport/session.rb +296 -0
  106. data/lib/net/ssh/transport/version-negotiator.rb +73 -0
  107. data/lib/net/ssh/userauth/agent.rb +218 -0
  108. data/lib/net/ssh/userauth/constants.rb +35 -0
  109. data/lib/net/ssh/userauth/driver.rb +176 -0
  110. data/lib/net/ssh/userauth/methods/hostbased.rb +119 -0
  111. data/lib/net/ssh/userauth/methods/password.rb +70 -0
  112. data/lib/net/ssh/userauth/methods/publickey.rb +137 -0
  113. data/lib/net/ssh/userauth/methods/services.rb +63 -0
  114. data/lib/net/ssh/userauth/services.rb +126 -0
  115. data/lib/net/ssh/userauth/userkeys.rb +258 -0
  116. data/lib/net/ssh/util/buffer.rb +274 -0
  117. data/lib/net/ssh/util/openssl.rb +146 -0
  118. data/lib/net/ssh/util/prompter.rb +73 -0
  119. data/lib/net/ssh/version.rb +29 -0
  120. data/test/ALL-TESTS.rb +21 -0
  121. data/test/connection/tc_channel.rb +136 -0
  122. data/test/connection/tc_driver.rb +287 -0
  123. data/test/connection/tc_integration.rb +85 -0
  124. data/test/proxy/tc_http.rb +209 -0
  125. data/test/proxy/tc_socks4.rb +148 -0
  126. data/test/proxy/tc_socks5.rb +214 -0
  127. data/test/service/forward/tc_driver.rb +289 -0
  128. data/test/service/forward/tc_local_network_handler.rb +123 -0
  129. data/test/service/forward/tc_remote_network_handler.rb +108 -0
  130. data/test/service/process/tc_driver.rb +79 -0
  131. data/test/service/process/tc_integration.rb +117 -0
  132. data/test/service/process/tc_open.rb +179 -0
  133. data/test/service/process/tc_popen3.rb +164 -0
  134. data/test/tc_integration.rb +79 -0
  135. data/test/transport/compress/tc_none_compress.rb +41 -0
  136. data/test/transport/compress/tc_none_decompress.rb +45 -0
  137. data/test/transport/compress/tc_zlib_compress.rb +61 -0
  138. data/test/transport/compress/tc_zlib_decompress.rb +48 -0
  139. data/test/transport/kex/tc_dh.rb +304 -0
  140. data/test/transport/kex/tc_dh_gex.rb +70 -0
  141. data/test/transport/ossl/fixtures/dsa-encrypted +15 -0
  142. data/test/transport/ossl/fixtures/dsa-encrypted-bad +15 -0
  143. data/test/transport/ossl/fixtures/dsa-unencrypted +12 -0
  144. data/test/transport/ossl/fixtures/dsa-unencrypted-bad +12 -0
  145. data/test/transport/ossl/fixtures/dsa-unencrypted.pub +1 -0
  146. data/test/transport/ossl/fixtures/not-a-private-key +4 -0
  147. data/test/transport/ossl/fixtures/not-supported +2 -0
  148. data/test/transport/ossl/fixtures/rsa-encrypted +18 -0
  149. data/test/transport/ossl/fixtures/rsa-encrypted-bad +18 -0
  150. data/test/transport/ossl/fixtures/rsa-unencrypted +15 -0
  151. data/test/transport/ossl/fixtures/rsa-unencrypted-bad +15 -0
  152. data/test/transport/ossl/fixtures/rsa-unencrypted.pub +1 -0
  153. data/test/transport/ossl/hmac/tc_hmac.rb +58 -0
  154. data/test/transport/ossl/hmac/tc_md5.rb +50 -0
  155. data/test/transport/ossl/hmac/tc_md5_96.rb +50 -0
  156. data/test/transport/ossl/hmac/tc_none.rb +50 -0
  157. data/test/transport/ossl/hmac/tc_sha1.rb +50 -0
  158. data/test/transport/ossl/hmac/tc_sha1_96.rb +50 -0
  159. data/test/transport/ossl/tc_buffer.rb +97 -0
  160. data/test/transport/ossl/tc_buffer_factory.rb +67 -0
  161. data/test/transport/ossl/tc_cipher_factory.rb +84 -0
  162. data/test/transport/ossl/tc_digest_factory.rb +39 -0
  163. data/test/transport/ossl/tc_hmac_factory.rb +72 -0
  164. data/test/transport/ossl/tc_key_factory.rb +199 -0
  165. data/test/transport/tc_algorithm_negotiator.rb +169 -0
  166. data/test/transport/tc_identity_cipher.rb +52 -0
  167. data/test/transport/tc_integration.rb +110 -0
  168. data/test/transport/tc_packet_stream.rb +183 -0
  169. data/test/transport/tc_session.rb +283 -0
  170. data/test/transport/tc_version_negotiator.rb +86 -0
  171. data/test/userauth/methods/tc_hostbased.rb +136 -0
  172. data/test/userauth/methods/tc_password.rb +89 -0
  173. data/test/userauth/methods/tc_publickey.rb +167 -0
  174. data/test/userauth/tc_agent.rb +223 -0
  175. data/test/userauth/tc_driver.rb +190 -0
  176. data/test/userauth/tc_integration.rb +81 -0
  177. data/test/userauth/tc_userkeys.rb +265 -0
  178. data/test/util/tc_buffer.rb +217 -0
  179. metadata +256 -0
@@ -0,0 +1,73 @@
1
+ #--
2
+ # =============================================================================
3
+ # Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
4
+ # All rights reserved.
5
+ #
6
+ # This source file is distributed as part of the Net::SSH Secure Shell Client
7
+ # library for Ruby. This file (and the library as a whole) may be used only as
8
+ # allowed by either the BSD license, or the Ruby license (or, by association
9
+ # with the Ruby license, the GPL). See the "doc" subdirectory of the Net::SSH
10
+ # distribution for the texts of these licenses.
11
+ # -----------------------------------------------------------------------------
12
+ # net-ssh website : http://net-ssh.rubyforge.org
13
+ # project website: http://rubyforge.org/projects/net-ssh
14
+ # =============================================================================
15
+ #++
16
+
17
+ require 'net/ssh/errors'
18
+
19
+ module Net
20
+ module SSH
21
+ module Transport
22
+
23
+ # Manages the negotiation of the version strings between client and
24
+ # server.
25
+ class VersionNegotiator
26
+
27
+ # For processing the version header. The version reported by the server
28
+ # must match this pattern.
29
+ VERSION_LINE = /^SSH-/
30
+
31
+ # Only versions matching this pattern are supported by Net::SSH.
32
+ REQUIRED_VERSION_PATTERN = /^SSH-(1.99|2.0)-/
33
+
34
+ # An array of lines returned by the server prior to reporting the
35
+ # version.
36
+ attr_reader :header_lines
37
+
38
+ # Creates a new VersionNegotiator object that logs to the given logger
39
+ # instance.
40
+ def initialize( logger )
41
+ @logger = logger
42
+ end
43
+
44
+ # Negotiate version information over the given socket. This will
45
+ # return the version reported by the server.
46
+ def negotiate( socket, version )
47
+ server_version = ""
48
+ @header_lines = []
49
+
50
+ loop do
51
+ server_version = socket.readline
52
+ break if server_version.nil? || VERSION_LINE.match( server_version )
53
+ @header_lines << server_version
54
+ end
55
+
56
+ if !REQUIRED_VERSION_PATTERN.match( server_version )
57
+ raise Net::SSH::Exception,
58
+ "incompatible ssh version #{server_version.inspect}"
59
+ end
60
+
61
+ if @logger.debug?
62
+ @logger.debug "remote server is #{server_version.chomp.inspect}"
63
+ end
64
+ socket.print "#{version}\r\n"
65
+
66
+ return server_version.chomp
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,218 @@
1
+ #--
2
+ # =============================================================================
3
+ # Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
4
+ # All rights reserved.
5
+ #
6
+ # This source file is distributed as part of the Net::SSH Secure Shell Client
7
+ # library for Ruby. This file (and the library as a whole) may be used only as
8
+ # allowed by either the BSD license, or the Ruby license (or, by association
9
+ # with the Ruby license, the GPL). See the "doc" subdirectory of the Net::SSH
10
+ # distribution for the texts of these licenses.
11
+ # -----------------------------------------------------------------------------
12
+ # net-ssh website : http://net-ssh.rubyforge.org
13
+ # project website: http://rubyforge.org/projects/net-ssh
14
+ # =============================================================================
15
+ #++
16
+
17
+ require 'net/ssh/errors'
18
+ require 'net/ssh/transport/session'
19
+
20
+ module Net
21
+ module SSH
22
+ module UserAuth
23
+
24
+ # A trivial exception class for representing agent-specific errors.
25
+ class AgentError < Net::SSH::Exception; end
26
+
27
+ # This class implements a simple client for the ssh-agent protocol. It
28
+ # does not implement any specific protocol, but instead copies the
29
+ # behavior of the ssh-agent functions in the OpenSSH library (3.8).
30
+ #
31
+ # This means that although it behaves like a SSH1 client, it also has
32
+ # some SSH2 functionality (like signing data).
33
+ #
34
+ # Also, this class relies on there being a UNIXSocket that the active
35
+ # ssh-agent is listening on. It expects that socket to exist at the
36
+ # location described by the SSH_AUTH_SOCK environment variable. Because
37
+ # of the dependency on UNIXSocket, the agent is not available under
38
+ # Windows, and I have no immediate plans to implement support for
39
+ # PuTTy's "pageant" utility.
40
+ class Agent
41
+ SSH2_AGENT_REQUEST_VERSION = 1
42
+ SSH2_AGENT_REQUEST_IDENTITIES = 11
43
+ SSH2_AGENT_IDENTITIES_ANSWER = 12
44
+ SSH2_AGENT_SIGN_REQUEST = 13
45
+ SSH2_AGENT_SIGN_RESPONSE = 14
46
+ SSH2_AGENT_FAILURE = 30
47
+ SSH2_AGENT_VERSION_RESPONSE = 103
48
+
49
+ SSH_COM_AGENT2_FAILURE = 102
50
+
51
+ SSH_AGENT_REQUEST_RSA_IDENTITIES = 1
52
+ SSH_AGENT_RSA_IDENTITIES_ANSWER = 2
53
+ SSH_AGENT_FAILURE = 5
54
+
55
+ # The socket factory used to connect to the agent process. It must
56
+ # respond to #open, and accept a single parameter (the name of the
57
+ # socket to open).
58
+ attr_writer :socket_factory
59
+
60
+ # The name of the socket to open.
61
+ attr_writer :socket_name
62
+
63
+ # The version of the SSH protocol version to report.
64
+ attr_writer :version
65
+
66
+ # The buffer factory to use to obtain buffer instances.
67
+ attr_writer :buffers
68
+
69
+ # The key factory to use to obtain key instances.
70
+ attr_writer :keys
71
+
72
+ # Connect to the agent process using the socket factory and socket name
73
+ # given by the attribute writers. If the agent on the other end of the
74
+ # socket reports that it is an SSH2-compatible agent, this will fail
75
+ # (it only supports the ssh-agent distributed by OpenSSH).
76
+ def connect!
77
+ @socket = @socket_factory.open( @socket_name )
78
+
79
+ # determine what type of agent we're communicating with
80
+ buffer = @buffers.writer
81
+ buffer.write_string Net::SSH::Transport::Session.version
82
+ type, body = send_with_reply SSH2_AGENT_REQUEST_VERSION, buffer
83
+
84
+ if type == SSH2_AGENT_VERSION_RESPONSE
85
+ raise NotImplementedError, "SSH2 agents are not yet supported"
86
+ elsif type != SSH_AGENT_RSA_IDENTITIES_ANSWER
87
+ raise AgentError,
88
+ "unknown response from agent: #{type}, #{body.to_s.inspect}"
89
+ end
90
+ end
91
+
92
+ # Return an array of all identities (public keys) known to the agent.
93
+ # Each key returned is augmented with a +comment+ property which is set
94
+ # to the comment returned by the agent for that key.
95
+ def identities
96
+ case @version
97
+ when 1
98
+ code1 = SSH_AGENT_REQUEST_RSA_IDENTITIES
99
+ code2 = SSH_AGENT_RSA_IDENTITIES_ANSWER
100
+ when 2
101
+ code1 = SSH2_AGENT_REQUEST_IDENTITIES
102
+ code2 = SSH2_AGENT_IDENTITIES_ANSWER
103
+ else
104
+ raise NotImplementedError, "SSH version #{@version}"
105
+ end
106
+
107
+ type, body = send_with_reply code1
108
+ raise AgentError,
109
+ "could not get identity count" if agent_failed( type )
110
+ raise AgentError, "bad authentication reply: #{type}" if type != code2
111
+
112
+ identities = []
113
+ body.read_long.times do
114
+ case @version
115
+ when 1
116
+ key = @keys.get( "rsa" )
117
+ bits = body.read_long
118
+ key.e = body.read_bignum
119
+ key.n = body.read_bignum
120
+ when 2
121
+ blob = @buffers.reader( body.read_string )
122
+ key = blob.read_key
123
+ end
124
+
125
+ unless key.respond_to?( :comment= )
126
+ key.instance_eval <<-EVAL
127
+ def comment=(cmt)
128
+ @comment = cmt
129
+ end
130
+ EVAL
131
+ end
132
+
133
+ unless key.respond_to?( :comment )
134
+ key.instance_eval <<-EVAL
135
+ def comment
136
+ @comment
137
+ end
138
+ EVAL
139
+ end
140
+
141
+ key.comment = body.read_string
142
+ identities.push key
143
+ end
144
+
145
+ return identities
146
+ end
147
+
148
+ # Closes this socket. This agent reference is no longer able to
149
+ # query the agent.
150
+ def close
151
+ @socket.close
152
+ end
153
+
154
+ # Using the agent and the given public key, sign the given data. The
155
+ # signature is returned in SSH2 format.
156
+ def sign( key, data )
157
+ blob = @buffers.writer
158
+ blob.write_key key
159
+
160
+ packet_data = @buffers.writer
161
+ packet_data.write_string blob.to_s
162
+ packet_data.write_string data.to_s
163
+ packet_data.write_long 0
164
+
165
+ type, reply = send_with_reply SSH2_AGENT_SIGN_REQUEST, packet_data
166
+ if agent_failed( type )
167
+ raise AgentError,
168
+ "agent could not sign data with requested identity"
169
+ elsif type != SSH2_AGENT_SIGN_RESPONSE
170
+ raise AgentError, "bad authentication response #{type}"
171
+ end
172
+
173
+ return reply.read_string
174
+ end
175
+
176
+ # Send a new packet of the given type, with the associated data.
177
+ def send_packet( type, data=nil )
178
+ buffer = @buffers.writer
179
+ buffer.write_long( ( data ? data.length : 0 ) + 1 )
180
+ buffer.write_byte type.to_i
181
+ buffer.write data.to_s if data
182
+ @socket.send buffer.to_s, 0
183
+ end
184
+ private :send_packet
185
+
186
+ # Read the next packet from the agent. This will return a two-part
187
+ # tuple consisting of the packet type, and the packet's body (which
188
+ # is returned as a Net::SSH::Util::ReaderBuffer).
189
+ def read_packet
190
+ length = @socket.read( 4 ).unpack( "N" ).first - 1
191
+ type = @socket.read( 1 ).unpack( "C" ).first
192
+ reader = @buffers.reader( @socket.read( length ) )
193
+ return type, reader
194
+ end
195
+ private :read_packet
196
+
197
+ # Send the given packet and return the subsequent reply from the agent.
198
+ # (See #send_packet and #read_packet).
199
+ def send_with_reply( type, data=nil )
200
+ send_packet type, data
201
+ read_packet
202
+ end
203
+ private :send_with_reply
204
+
205
+ # Returns +true+ if the parameter indicates a "failure" response from
206
+ # the agent, and +false+ otherwise.
207
+ def agent_failed( type )
208
+ type == SSH_AGENT_FAILURE ||
209
+ type == SSH2_AGENT_FAILURE ||
210
+ type == SSH_COM_AGENT2_FAILURE
211
+ end
212
+ private :agent_failed
213
+
214
+ end
215
+
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,35 @@
1
+ #--
2
+ # =============================================================================
3
+ # Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
4
+ # All rights reserved.
5
+ #
6
+ # This source file is distributed as part of the Net::SSH Secure Shell Client
7
+ # library for Ruby. This file (and the library as a whole) may be used only as
8
+ # allowed by either the BSD license, or the Ruby license (or, by association
9
+ # with the Ruby license, the GPL). See the "doc" subdirectory of the Net::SSH
10
+ # distribution for the texts of these licenses.
11
+ # -----------------------------------------------------------------------------
12
+ # net-ssh website : http://net-ssh.rubyforge.org
13
+ # project website: http://rubyforge.org/projects/net-ssh
14
+ # =============================================================================
15
+ #++
16
+
17
+ module Net
18
+ module SSH
19
+ module UserAuth
20
+
21
+ module Constants
22
+
23
+ USERAUTH_REQUEST = 50
24
+ USERAUTH_FAILURE = 51
25
+ USERAUTH_SUCCESS = 52
26
+ USERAUTH_BANNER = 53
27
+
28
+ USERAUTH_PASSWD_CHANGEREQ = 60
29
+ USERAUTH_PK_OK = 60
30
+
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,176 @@
1
+ #--
2
+ # =============================================================================
3
+ # Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
4
+ # All rights reserved.
5
+ #
6
+ # This source file is distributed as part of the Net::SSH Secure Shell Client
7
+ # library for Ruby. This file (and the library as a whole) may be used only as
8
+ # allowed by either the BSD license, or the Ruby license (or, by association
9
+ # with the Ruby license, the GPL). See the "doc" subdirectory of the Net::SSH
10
+ # distribution for the texts of these licenses.
11
+ # -----------------------------------------------------------------------------
12
+ # net-ssh website : http://net-ssh.rubyforge.org
13
+ # project website: http://rubyforge.org/projects/net-ssh
14
+ # =============================================================================
15
+ #++
16
+
17
+ require 'net/ssh/errors'
18
+ require 'net/ssh/userauth/constants'
19
+ require 'net/ssh/transport/constants'
20
+ require 'ostruct'
21
+
22
+ module Net
23
+ module SSH
24
+ module UserAuth
25
+
26
+ # A wrapper around the transport layer that represents the functionality
27
+ # of user authentication.
28
+ class Driver
29
+
30
+ include Net::SSH::UserAuth::Constants
31
+ include Net::SSH::Transport::Constants
32
+
33
+ # The UserKeyManager instance used by the auth service.
34
+ attr_writer :key_manager
35
+
36
+ # The SSH (transport) session to use for communication.
37
+ attr_writer :session
38
+
39
+ # The array of auth-method names (as strings), giving the order in
40
+ # which each auth-method will be tried.
41
+ attr_reader :order
42
+
43
+ # Create a new user-auth service on top of the given session.
44
+ def initialize( log, buffers, methods, order )
45
+ @log = log
46
+ @buffers = buffers
47
+ @methods = methods
48
+ @on_banner = proc { |msg,lang| puts msg }
49
+ @order = order.dup
50
+ end
51
+
52
+ # Causes the set of on-disk key files to be used to be set to the
53
+ # given array. Any key files that were specified previously are
54
+ # lost.
55
+ def set_key_files( files )
56
+ @key_manager.clear!
57
+ files.each { |file| @key_manager << file }
58
+ end
59
+
60
+ # Causes the set of on-disk host key files to be used to be set to the
61
+ # given array. Any host key files that were specified previously are
62
+ # lost.
63
+ def set_host_key_files( files )
64
+ @key_manager.clear_host!
65
+ files.each { |file| @key_manager.add_host_key file }
66
+ end
67
+
68
+ # Changes the set of authentication methods to try to the given array.
69
+ # Methods are tried in the order in which they are listed in the
70
+ # array.
71
+ def set_auth_method_order( *methods )
72
+ @order = methods.flatten
73
+ end
74
+
75
+ # Specify the callback to use when the server sends a banner message
76
+ # at login time.
77
+ def on_banner( &block )
78
+ @on_banner = block
79
+ end
80
+
81
+ # Sends the message by delegating to the session's #send_message
82
+ # method. (This is a convenience method for the authentication
83
+ # implementations.)
84
+ def send_message( message )
85
+ @session.send_message message
86
+ end
87
+
88
+ # Wraps the Net::SSH::Transport::Session#wait_for_message method,
89
+ # doing special checking for authentication-related messages.
90
+ def wait_for_message
91
+ loop do
92
+ type, buffer = @session.wait_for_message
93
+
94
+ case type
95
+ when USERAUTH_BANNER
96
+ message = buffer.read_string
97
+ language = buffer.read_string
98
+
99
+ if @log.debug?
100
+ @log.debug "got USERAUTH_BANNER (#{message}:#{language})"
101
+ end
102
+
103
+ @on_banner.call( message, language )
104
+
105
+ when USERAUTH_FAILURE
106
+ authentications = buffer.read_string
107
+ partial_success = buffer.read_bool
108
+ return OpenStruct.new( :message_type => type,
109
+ :authentications => authentications,
110
+ :partial_success => partial_success )
111
+
112
+ when USERAUTH_SUCCESS
113
+ return OpenStruct.new( :message_type => type )
114
+
115
+ when SERVICE_ACCEPT
116
+ return OpenStruct.new( :message_type => type,
117
+ :service_name => buffer.read_string )
118
+
119
+ # authmethod-specific codes
120
+ when 60..79
121
+ return OpenStruct.new( :message_type => type,
122
+ :buffer => buffer )
123
+
124
+ else
125
+ raise Net::SSH::Exception,
126
+ "unexpected message type '#{type}' (#{buffer.to_s})"
127
+ end
128
+ end
129
+ end
130
+
131
+ # Processes the authentication of the given username. The
132
+ # 'next_service' parameter should be set to the SSH service that will
133
+ # be requested once the authentication succeeds (usually
134
+ # 'ssh-connection').
135
+ #
136
+ # This will return +true+ if the user is accepted by the server, and
137
+ # +false+ otherwise.
138
+ def authenticate( next_service, username, password=nil )
139
+ msg = @buffers.writer
140
+ msg.write_byte SERVICE_REQUEST
141
+ msg.write_string "ssh-userauth"
142
+ send_message msg
143
+
144
+ message = wait_for_message
145
+ unless message.message_type == SERVICE_ACCEPT
146
+ raise Net::SSH::Exception,
147
+ "expected SERVICE_ACCEPT, got #{message.inspect}"
148
+ end
149
+
150
+ data = { :password => password,
151
+ :key_manager => @key_manager }
152
+
153
+ @order.each do |auth_method|
154
+ @log.debug "trying #{auth_method.inspect}" if @log.debug?
155
+
156
+ impl = @methods[ auth_method.downcase.gsub(/-/,"_").intern ]
157
+ if impl.nil?
158
+ raise NotImplementedError,
159
+ "`#{auth_method}' authentication is not implemented"
160
+ end
161
+
162
+ return true if impl.authenticate( next_service, username, data )
163
+ end
164
+
165
+ @log.debug "all authorization methods failed" if @log.debug?
166
+ return false
167
+
168
+ ensure
169
+ @key_manager.finish
170
+ end
171
+
172
+ end
173
+
174
+ end
175
+ end
176
+ end