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.


402
403
404
405
406
407
408
409
410
411
412
# File 'lib/net/ssh/authentication/pageant.rb', line 402

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

Class Method Details

.openObject

The factory method for creating a new Socket instance.


396
397
398
# File 'lib/net/ssh/authentication/pageant.rb', line 396

def self.open
  new
end

Instance Method Details

#closeObject


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

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.


436
437
438
# File 'lib/net/ssh/authentication/pageant.rb', line 436

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.


416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
# File 'lib/net/ssh/authentication/pageant.rb', line 416

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.


445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
# File 'lib/net/ssh/authentication/pageant.rb', line 445

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