Class: Net::SSH::Authentication::Pageant::Socket

Inherits:
Object
  • Object
show all
Defined in:
lib/net/ssh/authentication/pageant.rb

Overview

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.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeSocket

Create a new instance that communicates with the running pageant instance. If no such instance is running, this will cause an error.



283
284
285
286
287
288
289
290
291
292
293
# File 'lib/net/ssh/authentication/pageant.rb', line 283

def initialize
  @win = Win.FindWindow("Pageant", "Pageant")

  if @win == 0
    raise Net::SSH::Exception,
      "pageant process not running"
  end

  @input_buffer = Net::SSH::Buffer.new
  @output_buffer = Net::SSH::Buffer.new
end

Class Method Details

.open(location = nil) ⇒ Object

The factory method for creating a new Socket instance. The location parameter is ignored, and is only needed for compatibility with the general Socket interface.



277
278
279
# File 'lib/net/ssh/authentication/pageant.rb', line 277

def self.open(location=nil)
  new
end

Instance Method Details

#closeObject



319
320
# File 'lib/net/ssh/authentication/pageant.rb', line 319

def close
end

#read(n = nil) ⇒ Object

Reads n bytes from the cached result of the last query. If n is nil, returns all remaining data from the last query.



315
316
317
# File 'lib/net/ssh/authentication/pageant.rb', line 315

def read(n = nil)
  @output_buffer.read(n)
end

#send(data, *args) ⇒ Object

Forwards the data to #send_query, ignoring any arguments after the first.



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
# File 'lib/net/ssh/authentication/pageant.rb', line 297

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

#send_query(query) ⇒ Object

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.



325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
# File 'lib/net/ssh/authentication/pageant.rb', line 325

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)

  cds = Win.get_ptr [AGENT_COPYDATA_ID, mapname.size + 1,
                     Win.get_cstr(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)
  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