summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJavier Gonel <bolibic@gmail.com>2011-03-01 13:21:02 +0200
committerJavier Gonel <bolibic@gmail.com>2011-03-01 13:21:02 +0200
commita5ebe60f7f6652ea73238b2884e03b87cbac5231 (patch)
treeec8d8b588a1c5b8ff9b684770183a0c404d08d9c /lib
parentef230397fd0ad34ba12437c90660fc394c7e84bf (diff)
downloadnet-ssh-a5ebe60f7f6652ea73238b2884e03b87cbac5231.tar.gz
Adds support for Putty ssh agent and ruby 1.9 (Windows)
Diffstat (limited to 'lib')
-rw-r--r--lib/net/ssh/authentication/agent.rb6
-rw-r--r--lib/net/ssh/authentication/pageant.rb93
2 files changed, 90 insertions, 9 deletions
diff --git a/lib/net/ssh/authentication/agent.rb b/lib/net/ssh/authentication/agent.rb
index 1ff40aa..2208872 100644
--- a/lib/net/ssh/authentication/agent.rb
+++ b/lib/net/ssh/authentication/agent.rb
@@ -3,8 +3,8 @@ require 'net/ssh/errors'
require 'net/ssh/loggable'
require 'net/ssh/transport/server_version'
-# Only load pageant on Windows, Ruby 1.8.x
-if File::ALT_SEPARATOR && !(RUBY_PLATFORM =~ /java/) && RUBY_VERSION < "1.9"
+# Only load pageant on Windows
+if File::ALT_SEPARATOR && !(RUBY_PLATFORM =~ /java/)
require 'net/ssh/authentication/pageant'
end
@@ -135,7 +135,7 @@ module Net; module SSH; module Authentication
# Returns the agent socket factory to use.
def agent_socket_factory
if File::ALT_SEPARATOR
- Pageant::Socket
+ Pageant::socket_factory
else
UNIXSocket
end
diff --git a/lib/net/ssh/authentication/pageant.rb b/lib/net/ssh/authentication/pageant.rb
index 871e86b..9ec2fa7 100644
--- a/lib/net/ssh/authentication/pageant.rb
+++ b/lib/net/ssh/authentication/pageant.rb
@@ -1,5 +1,13 @@
require 'dl/import'
-require 'dl/struct'
+
+if RUBY_VERSION < "1.9"
+ require 'dl/struct'
+end
+
+if RUBY_VERSION =~ /^1.9/
+ require 'dl/types'
+ require 'dl'
+end
require 'net/ssh/errors'
@@ -21,10 +29,18 @@ module Net; module SSH; module Authentication
# The definition of the Windows methods and data structures used in
# communicating with the pageant process.
module Win
- extend DL::Importable
+ if RUBY_VERSION < "1.9"
+ extend DL::Importable
- dlload 'user32'
- dlload 'kernel32'
+ dlload 'user32'
+ dlload 'kernel32'
+ end
+
+ if RUBY_VERSION =~ /^1.9/
+ extend DL::Importer
+ dlload 'user32','kernel32'
+ include DL::Win32Types
+ end
typealias("LPCTSTR", "char *") # From winnt.h
typealias("LPVOID", "void *") # From winnt.h
@@ -67,8 +83,12 @@ module Net; module SSH; module Authentication
# args: hWnd, Msg, wParam, lParam, fuFlags, uTimeout, lpdwResult
extern 'LRESULT SendMessageTimeout(HWND, UINT, WPARAM, LPARAM, ' +
'UINT, UINT, PDWORD_PTR)'
+ if RUBY_VERSION < "1.9"
+ alias_method :FindWindow,:findWindow
+ module_function :FindWindow
+ end
end
-
+
# This is the pseudo-socket implementation that mimics the interface of
# a socket, translating each request into a Windows messaging call to
# the pageant daemon. This allows pageant support to be implemented
@@ -87,7 +107,7 @@ module Net; module SSH; module Authentication
# Create a new instance that communicates with the running pageant
# instance. If no such instance is running, this will cause an error.
def initialize
- @win = Win.findWindow("Pageant", "Pageant")
+ @win = Win.FindWindow("Pageant", "Pageant")
if @win == 0
raise Net::SSH::Exception,
@@ -177,7 +197,68 @@ module Net; module SSH; module Authentication
end
end
+
+ # Socket changes for Ruby 1.9
+ # Functionality is the same as Ruby 1.8 but it includes the new calls to
+ # the DL module as well as other pointer transformations
+ class Socket19 < Socket
+ # Packages the given query string and sends it to the pageant
+ # process via the Windows messaging subsystem. The result is
+ # cached, to be returned piece-wise when #read is called.
+ def send_query(query)
+ res = nil
+ filemap = 0
+ ptr = nil
+ id = DL.malloc(DL::SIZEOF_LONG)
+
+ mapname = "PageantRequest%08x\000" % Win.GetCurrentThreadId()
+
+ filemap = Win.CreateFileMapping(Win::INVALID_HANDLE_VALUE,
+ Win::NULL,
+ Win::PAGE_READWRITE, 0,
+ AGENT_MAX_MSGLEN, mapname)
+
+ if filemap == 0 || filemap == Win::INVALID_HANDLE_VALUE
+ raise Net::SSH::Exception,
+ "Creation of file mapping failed"
+ end
+
+ ptr = Win.MapViewOfFile(filemap, Win::FILE_MAP_WRITE, 0, 0,
+ 0)
+
+ if ptr.nil? || ptr.null?
+ raise Net::SSH::Exception, "Mapping of file failed"
+ end
+
+ DL::CPtr.new(ptr)[0,query.size]=query
+
+ cds = DL::CPtr.to_ptr [AGENT_COPYDATA_ID, mapname.size + 1, mapname].
+ pack("LLp")
+ succ = Win.SendMessageTimeout(@win, Win::WM_COPYDATA, Win::NULL,
+ cds, Win::SMTO_NORMAL, 5000, id)
+
+ if succ > 0
+ retlen = 4 + ptr.to_s(4).unpack("N")[0]
+ res = ptr.to_s(retlen)
+ end
+ return res
+ ensure
+ Win.UnmapViewOfFile(ptr) unless ptr.nil? || ptr.null?
+ Win.CloseHandle(filemap) if filemap != 0
+ end
+ end
+
+ # Selects which socket to use depending on the ruby version
+ # This is needed due changes in the DL module.
+ def self.socket_factory
+ if RUBY_VERSION < "1.9"
+ Socket
+ else
+ Socket19
+ end
+ end
+
end
end; end; end