diff options
| author | Javier Gonel <bolibic@gmail.com> | 2011-03-01 13:21:02 +0200 |
|---|---|---|
| committer | Javier Gonel <bolibic@gmail.com> | 2011-03-01 13:21:02 +0200 |
| commit | a5ebe60f7f6652ea73238b2884e03b87cbac5231 (patch) | |
| tree | ec8d8b588a1c5b8ff9b684770183a0c404d08d9c /lib | |
| parent | ef230397fd0ad34ba12437c90660fc394c7e84bf (diff) | |
| download | net-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.rb | 6 | ||||
| -rw-r--r-- | lib/net/ssh/authentication/pageant.rb | 93 |
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 |
