summaryrefslogtreecommitdiff
path: root/paramiko/win_pageant.py
diff options
context:
space:
mode:
Diffstat (limited to 'paramiko/win_pageant.py')
-rw-r--r--paramiko/win_pageant.py95
1 files changed, 36 insertions, 59 deletions
diff --git a/paramiko/win_pageant.py b/paramiko/win_pageant.py
index d77d58f..d588e81 100644
--- a/paramiko/win_pageant.py
+++ b/paramiko/win_pageant.py
@@ -8,7 +8,7 @@
# Software Foundation; either version 2.1 of the License, or (at your option)
# any later version.
#
-# Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY
+# Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
@@ -21,28 +21,20 @@
Functions for communicating with Pageant, the basic windows ssh agent program.
"""
-import os
-import struct
-import tempfile
-import mmap
+from __future__ import with_statement
+
import array
-import platform
import ctypes.wintypes
+import platform
+import struct
-# if you're on windows, you should have one of these, i guess?
-# ctypes is part of standard library since Python 2.5
-_has_win32all = False
-_has_ctypes = False
try:
- # win32gui is preferred over win32ui to avoid MFC dependencies
- import win32gui
- _has_win32all = True
+ import _thread as thread # Python 3.x
except ImportError:
- try:
- import ctypes
- _has_ctypes = True
- except ImportError:
- pass
+ import thread # Python 2.5-2.7
+
+from . import _winapi
+
_AGENT_COPYDATA_ID = 0x804e50ba
_AGENT_MAX_MSGLEN = 8192
@@ -52,16 +44,7 @@ win32con_WM_COPYDATA = 74
def _get_pageant_window_object():
- if _has_win32all:
- try:
- hwnd = win32gui.FindWindow('Pageant', 'Pageant')
- return hwnd
- except win32gui.error:
- pass
- elif _has_ctypes:
- # Return 0 if there is no Pageant window.
- return ctypes.windll.user32.FindWindowA('Pageant', 'Pageant')
- return None
+ return ctypes.windll.user32.FindWindowA('Pageant', 'Pageant')
def can_talk_to_agent():
@@ -71,11 +54,12 @@ def can_talk_to_agent():
This checks both if we have the required libraries (win32all or ctypes)
and if there is a Pageant currently running.
"""
- if (_has_win32all or _has_ctypes) and _get_pageant_window_object():
- return True
- return False
+ return bool(_get_pageant_window_object())
+
ULONG_PTR = ctypes.c_uint64 if platform.architecture()[0] == '64bit' else ctypes.c_uint32
+
+
class COPYDATASTRUCT(ctypes.Structure):
"""
ctypes implementation of
@@ -85,53 +69,46 @@ class COPYDATASTRUCT(ctypes.Structure):
('num_data', ULONG_PTR),
('data_size', ctypes.wintypes.DWORD),
('data_loc', ctypes.c_void_p),
- ]
+ ]
+
def _query_pageant(msg):
+ """
+ Communication with the Pageant process is done through a shared
+ memory-mapped file.
+ """
hwnd = _get_pageant_window_object()
if not hwnd:
# Raise a failure to connect exception, pageant isn't running anymore!
return None
- # Write our pageant request string into the file (pageant will read this to determine what to do)
- filename = tempfile.mktemp('.pag')
- map_filename = os.path.basename(filename)
-
- f = open(filename, 'w+b')
- f.write(msg )
- # Ensure the rest of the file is empty, otherwise pageant will read this
- f.write('\0' * (_AGENT_MAX_MSGLEN - len(msg)))
- # Create the shared file map that pageant will use to read from
- pymap = mmap.mmap(f.fileno(), _AGENT_MAX_MSGLEN, tagname=map_filename, access=mmap.ACCESS_WRITE)
- try:
+ # create a name for the mmap
+ map_name = 'PageantRequest%08x' % thread.get_ident()
+
+ pymap = _winapi.MemoryMap(map_name, _AGENT_MAX_MSGLEN,
+ _winapi.get_security_attributes_for_user(),
+ )
+ with pymap:
+ pymap.write(msg)
# Create an array buffer containing the mapped filename
- char_buffer = array.array("c", map_filename + '\0')
+ char_buffer = array.array("c", map_name + '\0')
char_buffer_address, char_buffer_size = char_buffer.buffer_info()
# Create a string to use for the SendMessage function call
- cds = COPYDATASTRUCT(_AGENT_COPYDATA_ID, char_buffer_size, char_buffer_address)
+ cds = COPYDATASTRUCT(_AGENT_COPYDATA_ID, char_buffer_size,
+ char_buffer_address)
- if _has_win32all:
- # win32gui.SendMessage should also allow the same pattern as
- # ctypes, but let's keep it like this for now...
- response = win32gui.SendMessage(hwnd, win32con_WM_COPYDATA, ctypes.sizeof(cds), ctypes.addressof(cds))
- elif _has_ctypes:
- response = ctypes.windll.user32.SendMessageA(hwnd, win32con_WM_COPYDATA, ctypes.sizeof(cds), ctypes.byref(cds))
- else:
- response = 0
+ response = ctypes.windll.user32.SendMessageA(hwnd,
+ win32con_WM_COPYDATA, ctypes.sizeof(cds), ctypes.byref(cds))
if response > 0:
+ pymap.seek(0)
datalen = pymap.read(4)
retlen = struct.unpack('>I', datalen)[0]
return datalen + pymap.read(retlen)
return None
- finally:
- pymap.close()
- f.close()
- # Remove the file, it was temporary only
- os.unlink(filename)
-class PageantConnection (object):
+class PageantConnection(object):
"""
Mock "connection" to an agent which roughly approximates the behavior of
a unix local-domain socket (as used by Agent). Requests are sent to the