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.


403
404
405
406
407
408
409
410
411
412
413
# 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

Class Method Details

.openObject

The factory method for creating a new Socket instance.


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

def self.open
  new
end

Instance Method Details

#closeObject


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

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.


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

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.


417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
# 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

#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.


444
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
# 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