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