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  import platform 
 30  import ctypes.wintypes 
 31   
 32  # if you're on windows, you should have one of these, i guess? 
 33  # ctypes is part of standard library since Python 2.5 
 34  _has_win32all = False 
 35  _has_ctypes = False 
 36  try: 
 37      # win32gui is preferred over win32ui to avoid MFC dependencies 
 38      import win32gui 
 39      _has_win32all = True 
 40  except ImportError: 
 41      try: 
 42          import ctypes 
 43          _has_ctypes = True 
 44      except ImportError: 
 45          pass 
 46   
 47  _AGENT_COPYDATA_ID = 0x804e50ba 
 48  _AGENT_MAX_MSGLEN = 8192 
 49  # Note: The WM_COPYDATA value is pulled from win32con, as a workaround 
 50  # so we do not have to import this huge library just for this one variable. 
 51  win32con_WM_COPYDATA = 74 
 52   
 53   
54 -def _get_pageant_window_object():
55 if _has_win32all: 56 try: 57 hwnd = win32gui.FindWindow('Pageant', 'Pageant') 58 return hwnd 59 except win32gui.error: 60 pass 61 elif _has_ctypes: 62 # Return 0 if there is no Pageant window. 63 return ctypes.windll.user32.FindWindowA('Pageant', 'Pageant') 64 return None
65 66
67 -def can_talk_to_agent():
68 """ 69 Check to see if there is a "Pageant" agent we can talk to. 70 71 This checks both if we have the required libraries (win32all or ctypes) 72 and if there is a Pageant currently running. 73 """ 74 if (_has_win32all or _has_ctypes) and _get_pageant_window_object(): 75 return True 76 return False
77 78 ULONG_PTR = ctypes.c_uint64 if platform.architecture()[0] == '64bit' else ctypes.c_uint32
79 -class COPYDATASTRUCT(ctypes.Structure):
80 """ 81 ctypes implementation of 82 http://msdn.microsoft.com/en-us/library/windows/desktop/ms649010%28v=vs.85%29.aspx 83 """ 84 _fields_ = [ 85 ('num_data', ULONG_PTR), 86 ('data_size', ctypes.wintypes.DWORD), 87 ('data_loc', ctypes.c_void_p), 88 ]
89
90 -def _query_pageant(msg):
91 hwnd = _get_pageant_window_object() 92 if not hwnd: 93 # Raise a failure to connect exception, pageant isn't running anymore! 94 return None 95 96 # Write our pageant request string into the file (pageant will read this to determine what to do) 97 filename = tempfile.mktemp('.pag') 98 map_filename = os.path.basename(filename) 99 100 f = open(filename, 'w+b') 101 f.write(msg ) 102 # Ensure the rest of the file is empty, otherwise pageant will read this 103 f.write('\0' * (_AGENT_MAX_MSGLEN - len(msg))) 104 # Create the shared file map that pageant will use to read from 105 pymap = mmap.mmap(f.fileno(), _AGENT_MAX_MSGLEN, tagname=map_filename, access=mmap.ACCESS_WRITE) 106 try: 107 # Create an array buffer containing the mapped filename 108 char_buffer = array.array("c", map_filename + '\0') 109 char_buffer_address, char_buffer_size = char_buffer.buffer_info() 110 # Create a string to use for the SendMessage function call 111 cds = COPYDATASTRUCT(_AGENT_COPYDATA_ID, char_buffer_size, char_buffer_address) 112 113 if _has_win32all: 114 # win32gui.SendMessage should also allow the same pattern as 115 # ctypes, but let's keep it like this for now... 116 response = win32gui.SendMessage(hwnd, win32con_WM_COPYDATA, ctypes.sizeof(cds), ctypes.addressof(cds)) 117 elif _has_ctypes: 118 response = ctypes.windll.user32.SendMessageA(hwnd, win32con_WM_COPYDATA, ctypes.sizeof(cds), ctypes.byref(cds)) 119 else: 120 response = 0 121 122 if response > 0: 123 datalen = pymap.read(4) 124 retlen = struct.unpack('>I', datalen)[0] 125 return datalen + pymap.read(retlen) 126 return None 127 finally: 128 pymap.close() 129 f.close() 130 # Remove the file, it was temporary only 131 os.unlink(filename)
132 133
134 -class PageantConnection (object):
135 """ 136 Mock "connection" to an agent which roughly approximates the behavior of 137 a unix local-domain socket (as used by Agent). Requests are sent to the 138 pageant daemon via special Windows magick, and responses are buffered back 139 for subsequent reads. 140 """ 141
142 - def __init__(self):
143 self._response = None
144
145 - def send(self, data):
146 self._response = _query_pageant(data)
147
148 - def recv(self, n):
149 if self._response is None: 150 return '' 151 ret = self._response[:n] 152 self._response = self._response[n:] 153 if self._response == '': 154 self._response = None 155 return ret
156
157 - def close(self):
158 pass
159