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