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 from __future__ import with_statement
25
26 import struct
27 import threading
28 import array
29 import platform
30 import ctypes.wintypes
31
32 from . import _winapi
33
34 _AGENT_COPYDATA_ID = 0x804e50ba
35 _AGENT_MAX_MSGLEN = 8192
36
37
38 win32con_WM_COPYDATA = 74
39
40
42 return ctypes.windll.user32.FindWindowA('Pageant', 'Pageant')
43
44
46 """
47 Check to see if there is a "Pageant" agent we can talk to.
48
49 This checks both if we have the required libraries (win32all or ctypes)
50 and if there is a Pageant currently running.
51 """
52 return bool(_get_pageant_window_object())
53
54 ULONG_PTR = ctypes.c_uint64 if platform.architecture()[0] == '64bit' else ctypes.c_uint32
56 """
57 ctypes implementation of
58 http://msdn.microsoft.com/en-us/library/windows/desktop/ms649010%28v=vs.85%29.aspx
59 """
60 _fields_ = [
61 ('num_data', ULONG_PTR),
62 ('data_size', ctypes.wintypes.DWORD),
63 ('data_loc', ctypes.c_void_p),
64 ]
65
67 """
68 Communication with the Pageant process is done through a shared
69 memory-mapped file.
70 """
71 hwnd = _get_pageant_window_object()
72 if not hwnd:
73
74 return None
75
76
77 map_name = 'PageantRequest%08x' % threading.current_thread().ident
78
79 pymap = _winapi.MemoryMap(map_name, _AGENT_MAX_MSGLEN,
80 _winapi.get_security_attributes_for_user(),
81 )
82 with pymap:
83 pymap.write(msg)
84
85 char_buffer = array.array("c", map_name + '\0')
86 char_buffer_address, char_buffer_size = char_buffer.buffer_info()
87
88 cds = COPYDATASTRUCT(_AGENT_COPYDATA_ID, char_buffer_size,
89 char_buffer_address)
90
91 response = ctypes.windll.user32.SendMessageA(hwnd,
92 win32con_WM_COPYDATA, ctypes.sizeof(cds), ctypes.byref(cds))
93
94 if response > 0:
95 pymap.seek(0)
96 datalen = pymap.read(4)
97 retlen = struct.unpack('>I', datalen)[0]
98 return datalen + pymap.read(retlen)
99 return None
100
101 -class PageantConnection (object):
102 """
103 Mock "connection" to an agent which roughly approximates the behavior of
104 a unix local-domain socket (as used by Agent). Requests are sent to the
105 pageant daemon via special Windows magick, and responses are buffered back
106 for subsequent reads.
107 """
108
109 - def __init__(self):
110 self._response = None
111
112 - def send(self, data):
113 self._response = _query_pageant(data)
114
116 if self._response is None:
117 return ''
118 ret = self._response[:n]
119 self._response = self._response[n:]
120 if self._response == '':
121 self._response = None
122 return ret
123
126