paramiko.win_pageant

Package paramiko :: Module win_pageant |
[frames] | no frames]

# Source Code for Module paramiko.win_pageant

      1  # Copyright (C) 2005 John Arbash-Meinel <john@arbash-meinel.com>
      2  # Modified up by: Todd Whiteman <ToddW@ActiveState.com>
      3  #
      4  # This file is part of paramiko.
      5  #
      6  # Paramiko is free software; you can redistribute it and/or modify it under the
      7  # terms of the GNU Lesser General Public License as published by the Free
      8  # Software Foundation; either version 2.1 of the License, or (at your option)
      9  # any later version.
     10  #
     11  # Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY
     12  # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     13  # A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
     14  # details.
     15  #
     16  # You should have received a copy of the GNU Lesser General Public License
     17  # along with Paramiko; if not, write to the Free Software Foundation, Inc.,
     18  # 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
     19
     20  """
     21  Functions for communicating with Pageant, the basic windows ssh agent program.
     22  """
     23
     24  import os
     25  import struct
     26  import tempfile
     27  import mmap
     28  import array
     29
     30  # if you're on windows, you should have one of these, i guess?
     31  # ctypes is part of standard library since Python 2.5
     32  _has_win32all = False
     33  _has_ctypes = False
     34  try:
     35      import win32ui
     36      _has_win32all = True
     37  except ImportError:
     38      try:
     39          import ctypes
     40          _has_ctypes = True
     41      except ImportError:
     42          pass
     43
     44
     45  _AGENT_COPYDATA_ID = 0x804e50ba
     46  _AGENT_MAX_MSGLEN = 8192
     47  # Note: The WM_COPYDATA value is pulled from win32con, as a workaround
     48  # so we do not have to import this huge library just for this one variable.
     49  win32con_WM_COPYDATA = 74
     50
     51
     52 -def _get_pageant_window_object():
     53      if _has_win32all:
     54          try:
     55              hwnd = win32ui.FindWindow('Pageant', 'Pageant')
     56              return hwnd
     57          except win32ui.error:
     58              pass
     59      elif _has_ctypes:
     60          # Return 0 if there is no Pageant window.
     61          return ctypes.windll.user32.FindWindowA('Pageant', 'Pageant')
     62      return None
     63
     64
     65 -def can_talk_to_agent():
     66      """
     67      Check to see if there is a "Pageant" agent we can talk to.
     68
     69      This checks both if we have the required libraries (win32all or ctypes)
     70      and if there is a Pageant currently running.
     71      """
     72      if (_has_win32all or _has_ctypes) and _get_pageant_window_object():
     73          return True
     74      return False
     75
     76
     77 -def _query_pageant(msg):
     78      hwnd = _get_pageant_window_object()
     79      if not hwnd:
     80          # Raise a failure to connect exception, pageant isn't running anymore!
     81          return None
     82
     83      # Write our pageant request string into the file (pageant will read this to determine what to do)
     84      filename = tempfile.mktemp('.pag')
     85      map_filename = os.path.basename(filename)
     86
     87      f = open(filename, 'w+b')
     88      f.write(msg )
     89      # Ensure the rest of the file is empty, otherwise pageant will read this
     90      f.write('\0' * (_AGENT_MAX_MSGLEN - len(msg)))
     91      # Create the shared file map that pageant will use to read from
     92      pymap = mmap.mmap(f.fileno(), _AGENT_MAX_MSGLEN, tagname=map_filename, access=mmap.ACCESS_WRITE)
     93      try:
     94          # Create an array buffer containing the mapped filename
     95          char_buffer = array.array("c", map_filename + '\0')
     96          char_buffer_address, char_buffer_size = char_buffer.buffer_info()
     97          # Create a string to use for the SendMessage function call
     98          cds = struct.pack("LLP", _AGENT_COPYDATA_ID, char_buffer_size, char_buffer_address)
     99
    100          if _has_win32all:
    101              response = hwnd.SendMessage(win32con_WM_COPYDATA, cds)
    102          elif _has_ctypes:
    103              _buf = array.array('B', cds)
    104              _addr, _size = _buf.buffer_info()
    105              response = ctypes.windll.user32.SendMessageA(hwnd, win32con_WM_COPYDATA, _size, _addr)
    106          else:
    107              response = 0
    108
    109          if response > 0:
    110              datalen = pymap.read(4)
    111              retlen = struct.unpack('>I', datalen)[0]
    112              return datalen + pymap.read(retlen)
    113          return None
    114      finally:
    115          pymap.close()
    116          f.close()
    117          # Remove the file, it was temporary only
    118          os.unlink(filename)
    119
    120
    121 -class PageantConnection (object):
    122      """
    123      Mock "connection" to an agent which roughly approximates the behavior of
    124      a unix local-domain socket (as used by Agent).  Requests are sent to the
    125      pageant daemon via special Windows magick, and responses are buffered back
    126      for subsequent reads.
    127      """
    128
    129 -    def __init__(self):
    130          self._response = None
    131
    132 -    def send(self, data):
    133          self._response = _query_pageant(data)
    134
    135 -    def recv(self, n):
    136          if self._response is None:
    137              return ''
    138          ret = self._response[:n]
    139          self._response = self._response[n:]
    140          if self._response == '':
    141              self._response = None
    142          return ret
    143
    144 -    def close(self):
    145          pass
    146