1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
33
34 _has_win32all = False
35 _has_ctypes = False
36 try:
37
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
50
51 win32con_WM_COPYDATA = 74
52
53
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
63 return ctypes.windll.user32.FindWindowA('Pageant', 'Pageant')
64 return None
65
66
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
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
91 hwnd = _get_pageant_window_object()
92 if not hwnd:
93
94 return None
95
96
97 filename = tempfile.mktemp('.pag')
98 map_filename = os.path.basename(filename)
99
100 f = open(filename, 'w+b')
101 f.write(msg )
102
103 f.write('\0' * (_AGENT_MAX_MSGLEN - len(msg)))
104
105 pymap = mmap.mmap(f.fileno(), _AGENT_MAX_MSGLEN, tagname=map_filename, access=mmap.ACCESS_WRITE)
106 try:
107
108 char_buffer = array.array("c", map_filename + '\0')
109 char_buffer_address, char_buffer_size = char_buffer.buffer_info()
110
111 cds = COPYDATASTRUCT(_AGENT_COPYDATA_ID, char_buffer_size, char_buffer_address)
112
113 if _has_win32all:
114
115
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
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
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
159