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.
- data/doc/LICENSE-BSD +27 -0
- data/doc/LICENSE-GPL +280 -0
- data/doc/LICENSE-RUBY +56 -0
- data/doc/README +13 -0
- data/doc/manual-html/chapter-1.html +333 -0
- data/doc/manual-html/chapter-2.html +455 -0
- data/doc/manual-html/chapter-3.html +413 -0
- data/doc/manual-html/chapter-4.html +353 -0
- data/doc/manual-html/chapter-5.html +393 -0
- data/doc/manual-html/chapter-6.html +296 -0
- data/doc/manual-html/index.html +217 -0
- data/doc/manual-html/manual.css +192 -0
- data/doc/manual/chapter.erb +18 -0
- data/doc/manual/example.erb +18 -0
- data/doc/manual/index.erb +29 -0
- data/doc/manual/manual.css +192 -0
- data/doc/manual/manual.rb +240 -0
- data/doc/manual/manual.yml +67 -0
- data/doc/manual/page.erb +87 -0
- data/doc/manual/parts/channels_callbacks.txt +32 -0
- data/doc/manual/parts/channels_loop.txt +14 -0
- data/doc/manual/parts/channels_open.txt +20 -0
- data/doc/manual/parts/channels_operations.txt +15 -0
- data/doc/manual/parts/channels_types.txt +3 -0
- data/doc/manual/parts/channels_what_are.txt +7 -0
- data/doc/manual/parts/exec_channels.txt +28 -0
- data/doc/manual/parts/exec_open.txt +51 -0
- data/doc/manual/parts/exec_popen3.txt +35 -0
- data/doc/manual/parts/forward_direct.txt +37 -0
- data/doc/manual/parts/forward_handlers.txt +16 -0
- data/doc/manual/parts/forward_intro.txt +18 -0
- data/doc/manual/parts/forward_local.txt +18 -0
- data/doc/manual/parts/forward_remote.txt +14 -0
- data/doc/manual/parts/intro_author.txt +1 -0
- data/doc/manual/parts/intro_getting.txt +39 -0
- data/doc/manual/parts/intro_license.txt +6 -0
- data/doc/manual/parts/intro_support.txt +7 -0
- data/doc/manual/parts/intro_what_is.txt +7 -0
- data/doc/manual/parts/intro_what_is_not.txt +3 -0
- data/doc/manual/parts/proxy_http.txt +52 -0
- data/doc/manual/parts/proxy_intro.txt +1 -0
- data/doc/manual/parts/proxy_socks.txt +23 -0
- data/doc/manual/parts/session_key.txt +66 -0
- data/doc/manual/parts/session_options.txt +42 -0
- data/doc/manual/parts/session_session.txt +14 -0
- data/doc/manual/parts/session_start.txt +49 -0
- data/doc/manual/tutorial.erb +30 -0
- data/examples/channel-demo.rb +81 -0
- data/examples/port-forward.rb +51 -0
- data/examples/process-demo.rb +91 -0
- data/examples/remote-net-port-forward.rb +45 -0
- data/examples/remote-port-forward.rb +80 -0
- data/examples/tail-demo.rb +49 -0
- data/lib/net/ssh.rb +52 -0
- data/lib/net/ssh/connection/channel.rb +411 -0
- data/lib/net/ssh/connection/constants.rb +47 -0
- data/lib/net/ssh/connection/driver.rb +343 -0
- data/lib/net/ssh/connection/services.rb +72 -0
- data/lib/net/ssh/connection/term.rb +90 -0
- data/lib/net/ssh/errors.rb +27 -0
- data/lib/net/ssh/proxy/errors.rb +34 -0
- data/lib/net/ssh/proxy/http.rb +126 -0
- data/lib/net/ssh/proxy/socks4.rb +83 -0
- data/lib/net/ssh/proxy/socks5.rb +160 -0
- data/lib/net/ssh/service/forward/driver.rb +319 -0
- data/lib/net/ssh/service/forward/local-network-handler.rb +74 -0
- data/lib/net/ssh/service/forward/remote-network-handler.rb +81 -0
- data/lib/net/ssh/service/forward/services.rb +76 -0
- data/lib/net/ssh/service/process/driver.rb +153 -0
- data/lib/net/ssh/service/process/open.rb +193 -0
- data/lib/net/ssh/service/process/popen3.rb +160 -0
- data/lib/net/ssh/service/process/services.rb +66 -0
- data/lib/net/ssh/service/services.rb +44 -0
- data/lib/net/ssh/session.rb +242 -0
- data/lib/net/ssh/transport/algorithm-negotiator.rb +267 -0
- data/lib/net/ssh/transport/compress/compressor.rb +53 -0
- data/lib/net/ssh/transport/compress/decompressor.rb +53 -0
- data/lib/net/ssh/transport/compress/none-compressor.rb +39 -0
- data/lib/net/ssh/transport/compress/none-decompressor.rb +39 -0
- data/lib/net/ssh/transport/compress/services.rb +68 -0
- data/lib/net/ssh/transport/compress/zlib-compressor.rb +60 -0
- data/lib/net/ssh/transport/compress/zlib-decompressor.rb +52 -0
- data/lib/net/ssh/transport/constants.rb +66 -0
- data/lib/net/ssh/transport/errors.rb +47 -0
- data/lib/net/ssh/transport/identity-cipher.rb +61 -0
- data/lib/net/ssh/transport/kex/dh-gex.rb +106 -0
- data/lib/net/ssh/transport/kex/dh.rb +231 -0
- data/lib/net/ssh/transport/kex/services.rb +60 -0
- data/lib/net/ssh/transport/ossl/buffer-factory.rb +52 -0
- data/lib/net/ssh/transport/ossl/buffer.rb +87 -0
- data/lib/net/ssh/transport/ossl/cipher-factory.rb +98 -0
- data/lib/net/ssh/transport/ossl/digest-factory.rb +51 -0
- data/lib/net/ssh/transport/ossl/hmac-factory.rb +71 -0
- data/lib/net/ssh/transport/ossl/hmac/hmac.rb +62 -0
- data/lib/net/ssh/transport/ossl/hmac/md5-96.rb +44 -0
- data/lib/net/ssh/transport/ossl/hmac/md5.rb +46 -0
- data/lib/net/ssh/transport/ossl/hmac/none.rb +46 -0
- data/lib/net/ssh/transport/ossl/hmac/services.rb +68 -0
- data/lib/net/ssh/transport/ossl/hmac/sha1-96.rb +44 -0
- data/lib/net/ssh/transport/ossl/hmac/sha1.rb +45 -0
- data/lib/net/ssh/transport/ossl/key-factory.rb +113 -0
- data/lib/net/ssh/transport/ossl/services.rb +149 -0
- data/lib/net/ssh/transport/packet-stream.rb +210 -0
- data/lib/net/ssh/transport/services.rb +146 -0
- data/lib/net/ssh/transport/session.rb +296 -0
- data/lib/net/ssh/transport/version-negotiator.rb +73 -0
- data/lib/net/ssh/userauth/agent.rb +218 -0
- data/lib/net/ssh/userauth/constants.rb +35 -0
- data/lib/net/ssh/userauth/driver.rb +176 -0
- data/lib/net/ssh/userauth/methods/hostbased.rb +119 -0
- data/lib/net/ssh/userauth/methods/password.rb +70 -0
- data/lib/net/ssh/userauth/methods/publickey.rb +137 -0
- data/lib/net/ssh/userauth/methods/services.rb +63 -0
- data/lib/net/ssh/userauth/services.rb +126 -0
- data/lib/net/ssh/userauth/userkeys.rb +258 -0
- data/lib/net/ssh/util/buffer.rb +274 -0
- data/lib/net/ssh/util/openssl.rb +146 -0
- data/lib/net/ssh/util/prompter.rb +73 -0
- data/lib/net/ssh/version.rb +29 -0
- data/test/ALL-TESTS.rb +21 -0
- data/test/connection/tc_channel.rb +136 -0
- data/test/connection/tc_driver.rb +287 -0
- data/test/connection/tc_integration.rb +85 -0
- data/test/proxy/tc_http.rb +209 -0
- data/test/proxy/tc_socks4.rb +148 -0
- data/test/proxy/tc_socks5.rb +214 -0
- data/test/service/forward/tc_driver.rb +289 -0
- data/test/service/forward/tc_local_network_handler.rb +123 -0
- data/test/service/forward/tc_remote_network_handler.rb +108 -0
- data/test/service/process/tc_driver.rb +79 -0
- data/test/service/process/tc_integration.rb +117 -0
- data/test/service/process/tc_open.rb +179 -0
- data/test/service/process/tc_popen3.rb +164 -0
- data/test/tc_integration.rb +79 -0
- data/test/transport/compress/tc_none_compress.rb +41 -0
- data/test/transport/compress/tc_none_decompress.rb +45 -0
- data/test/transport/compress/tc_zlib_compress.rb +61 -0
- data/test/transport/compress/tc_zlib_decompress.rb +48 -0
- data/test/transport/kex/tc_dh.rb +304 -0
- data/test/transport/kex/tc_dh_gex.rb +70 -0
- data/test/transport/ossl/fixtures/dsa-encrypted +15 -0
- data/test/transport/ossl/fixtures/dsa-encrypted-bad +15 -0
- data/test/transport/ossl/fixtures/dsa-unencrypted +12 -0
- data/test/transport/ossl/fixtures/dsa-unencrypted-bad +12 -0
- data/test/transport/ossl/fixtures/dsa-unencrypted.pub +1 -0
- data/test/transport/ossl/fixtures/not-a-private-key +4 -0
- data/test/transport/ossl/fixtures/not-supported +2 -0
- data/test/transport/ossl/fixtures/rsa-encrypted +18 -0
- data/test/transport/ossl/fixtures/rsa-encrypted-bad +18 -0
- data/test/transport/ossl/fixtures/rsa-unencrypted +15 -0
- data/test/transport/ossl/fixtures/rsa-unencrypted-bad +15 -0
- data/test/transport/ossl/fixtures/rsa-unencrypted.pub +1 -0
- data/test/transport/ossl/hmac/tc_hmac.rb +58 -0
- data/test/transport/ossl/hmac/tc_md5.rb +50 -0
- data/test/transport/ossl/hmac/tc_md5_96.rb +50 -0
- data/test/transport/ossl/hmac/tc_none.rb +50 -0
- data/test/transport/ossl/hmac/tc_sha1.rb +50 -0
- data/test/transport/ossl/hmac/tc_sha1_96.rb +50 -0
- data/test/transport/ossl/tc_buffer.rb +97 -0
- data/test/transport/ossl/tc_buffer_factory.rb +67 -0
- data/test/transport/ossl/tc_cipher_factory.rb +84 -0
- data/test/transport/ossl/tc_digest_factory.rb +39 -0
- data/test/transport/ossl/tc_hmac_factory.rb +72 -0
- data/test/transport/ossl/tc_key_factory.rb +199 -0
- data/test/transport/tc_algorithm_negotiator.rb +169 -0
- data/test/transport/tc_identity_cipher.rb +52 -0
- data/test/transport/tc_integration.rb +110 -0
- data/test/transport/tc_packet_stream.rb +183 -0
- data/test/transport/tc_session.rb +283 -0
- data/test/transport/tc_version_negotiator.rb +86 -0
- data/test/userauth/methods/tc_hostbased.rb +136 -0
- data/test/userauth/methods/tc_password.rb +89 -0
- data/test/userauth/methods/tc_publickey.rb +167 -0
- data/test/userauth/tc_agent.rb +223 -0
- data/test/userauth/tc_driver.rb +190 -0
- data/test/userauth/tc_integration.rb +81 -0
- data/test/userauth/tc_userkeys.rb +265 -0
- data/test/util/tc_buffer.rb +217 -0
- 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
|