1
# Copyright (C) 2005 John Arbash-Meinel <john@arbash-meinel.com>
2
# Modified up by: Todd Whiteman <ToddW@ActiveState.com>
4
# This file is part of paramiko.
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)
11
# Paramiko is distributed 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
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.
21
Functions for communicating with Pageant, the basic windows ssh agent program.
25
import ctypes.wintypes
28
from paramiko.common import zero_byte
29
from paramiko.py3compat import b
32
import _thread as thread # Python 3.x
34
import thread # Python 2.5-2.7
39
_AGENT_COPYDATA_ID = 0x804e50ba
40
_AGENT_MAX_MSGLEN = 8192
41
# Note: The WM_COPYDATA value is pulled from win32con, as a workaround
42
# so we do not have to import this huge library just for this one variable.
43
win32con_WM_COPYDATA = 74
46
def _get_pageant_window_object():
47
return ctypes.windll.user32.FindWindowA(b'Pageant', b'Pageant')
50
def can_talk_to_agent():
52
Check to see if there is a "Pageant" agent we can talk to.
54
This checks both if we have the required libraries (win32all or ctypes)
55
and if there is a Pageant currently running.
57
return bool(_get_pageant_window_object())
60
if platform.architecture()[0] == '64bit':
61
ULONG_PTR = ctypes.c_uint64
63
ULONG_PTR = ctypes.c_uint32
66
class COPYDATASTRUCT(ctypes.Structure):
68
ctypes implementation of
69
http://msdn.microsoft.com/en-us/library/windows/desktop/ms649010%28v=vs.85%29.aspx
72
('num_data', ULONG_PTR),
73
('data_size', ctypes.wintypes.DWORD),
74
('data_loc', ctypes.c_void_p),
78
def _query_pageant(msg):
80
Communication with the Pageant process is done through a shared
83
hwnd = _get_pageant_window_object()
85
# Raise a failure to connect exception, pageant isn't running anymore!
88
# create a name for the mmap
89
map_name = 'PageantRequest%08x' % thread.get_ident()
91
pymap = _winapi.MemoryMap(map_name, _AGENT_MAX_MSGLEN,
92
_winapi.get_security_attributes_for_user(),
96
# Create an array buffer containing the mapped filename
97
char_buffer = array.array("b", b(map_name) + zero_byte) # noqa
98
char_buffer_address, char_buffer_size = char_buffer.buffer_info()
99
# Create a string to use for the SendMessage function call
100
cds = COPYDATASTRUCT(_AGENT_COPYDATA_ID, char_buffer_size,
103
response = ctypes.windll.user32.SendMessageA(hwnd,
104
win32con_WM_COPYDATA, ctypes.sizeof(cds), ctypes.byref(cds))
108
datalen = pymap.read(4)
109
retlen = struct.unpack('>I', datalen)[0]
110
return datalen + pymap.read(retlen)
114
class PageantConnection(object):
116
Mock "connection" to an agent which roughly approximates the behavior of
117
a unix local-domain socket (as used by Agent). Requests are sent to the
118
pageant daemon via special Windows magick, and responses are buffered back
119
for subsequent reads.
123
self._response = None
125
def send(self, data):
126
self._response = _query_pageant(data)
129
if self._response is None:
131
ret = self._response[:n]
132
self._response = self._response[n:]
133
if self._response == '':
134
self._response = None