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.


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

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.


292
293
294
# File 'lib/net/ssh/authentication/pageant.rb', line 292

def self.open(location=nil)
  new
end

Instance Method Details

#closeObject


334
335
# File 'lib/net/ssh/authentication/pageant.rb', line 334

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.


330
331
332
# File 'lib/net/ssh/authentication/pageant.rb', line 330

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.


312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
# File 'lib/net/ssh/authentication/pageant.rb', line 312

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.


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
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
# File 'lib/net/ssh/authentication/pageant.rb', line 340

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