class Net::SSH::Authentication::Pageant::Socket
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 simply by replacing the socket factory used by the Agent class.
Public Class Methods
Create a new instance that communicates with the running pageant instance. If no such instance is running, this will cause an error.
# File lib/net/ssh/authentication/pageant.rb, line 403 def initialize @win = Win.FindWindow("Pageant", "Pageant") if @win.to_i == 0 raise Net::SSH::Exception, "pageant process not running" end @input_buffer = Net::SSH::Buffer.new @output_buffer = Net::SSH::Buffer.new end
The factory method for creating a new Socket instance.
# File lib/net/ssh/authentication/pageant.rb, line 397 def self.open new end
Public Instance Methods
# File lib/net/ssh/authentication/pageant.rb, line 439 def close; end
Reads n
bytes from the cached result of the last query. If
n
is nil
, returns all remaining data from the
last query.
# File lib/net/ssh/authentication/pageant.rb, line 435 def read(n = nil) @output_buffer.read(n) end
Forwards the data to send_query, ignoring any arguments after the first.
# File lib/net/ssh/authentication/pageant.rb, line 417 def send(data, *args) @input_buffer.append(data) ret = data.length while true return ret if @input_buffer.length < 4 msg_length = @input_buffer.read_long + 4 @input_buffer.reset! return ret if @input_buffer.length < msg_length msg = @input_buffer.read!(msg_length) @output_buffer.append(send_query(msg)) end end
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.
# File lib/net/ssh/authentication/pageant.rb, line 444 def send_query(query) res = nil filemap = 0 ptr = nil id = Win.malloc_ptr(Win::SIZEOF_DWORD) mapname = "PageantRequest%08x" % Win.GetCurrentThreadId() security_attributes = Win.get_ptr Win.get_security_attributes_for_user filemap = Win.CreateFileMapping(Win::INVALID_HANDLE_VALUE, security_attributes, 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 with error: #{Win.GetLastError}" 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 Win.set_ptr_data(ptr, query) # using struct to achieve proper alignment and field size on 64-bit platform cds = Win::COPYDATASTRUCT.new(Win.malloc_ptr(Win::COPYDATASTRUCT.size)) cds.dwData = AGENT_COPYDATA_ID cds.cbData = mapname.size + 1 cds.lpData = Win.get_cstr(mapname) succ = Win.SendMessageTimeout(@win, Win::WM_COPYDATA, Win::NULL, cds.to_ptr, Win::SMTO_NORMAL, 5000, id) if succ > 0 retlen = 4 + ptr.to_s(4).unpack("N")[0] res = ptr.to_s(retlen) else raise Net::SSH::Exception, "Message failed with error: #{Win.GetLastError}" end return res ensure Win.UnmapViewOfFile(ptr) unless ptr.nil? || ptr.null? Win.CloseHandle(filemap) if filemap != 0 end