From d8738b1b0f10e2f70ac69c3e3dbf10e496c8a67f Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Fri, 25 Oct 2013 14:28:52 +0300 Subject: [PATCH 1/6] Fix #193 (use RtlMoveMemory instead of msvcrt.memcpy) --- paramiko/_winapi.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/paramiko/_winapi.py b/paramiko/_winapi.py index f141b00..9af8add 100644 --- a/paramiko/_winapi.py +++ b/paramiko/_winapi.py @@ -81,9 +81,6 @@ def handle_nonzero_success(result): raise WindowsError() -##################### -# jaraco.windows.mmap - CreateFileMapping = ctypes.windll.kernel32.CreateFileMappingW CreateFileMapping.argtypes = [ ctypes.wintypes.HANDLE, @@ -130,15 +127,18 @@ class MemoryMap(object): self.pos = pos def write(self, msg): - ctypes.windll.msvcrt.memcpy(self.view + self.pos, msg, len(msg)) - self.pos += len(msg) + n = len(msg) + if self.pos + n >= self.length: # A little safety. + raise ValueError("Refusing to write %d bytes" % n) + ctypes.windll.kernel32.RtlMoveMemory(self.view + self.pos, msg, n) + self.pos += n def read(self, n): """ Read n bytes from mapped view. """ out = ctypes.create_string_buffer(n) - ctypes.windll.msvcrt.memcpy(out, self.view + self.pos, n) + ctypes.windll.kernel32.RtlMoveMemory(out, self.view + self.pos, n) self.pos += n return out.raw From d32d457775224c7afa12456810603def13bdc6a6 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Mon, 20 Jan 2014 22:47:04 +0200 Subject: [PATCH 2/6] Fix agent auth on Windows/Python 2.5) (with thanks to @lndbrg) --- paramiko/_winapi.py | 7 ++++++- paramiko/win_pageant.py | 8 ++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/paramiko/_winapi.py b/paramiko/_winapi.py index 9af8add..b875924 100644 --- a/paramiko/_winapi.py +++ b/paramiko/_winapi.py @@ -10,6 +10,11 @@ import ctypes import ctypes.wintypes import __builtin__ +try: + USHORT = ctypes.wintypes.USHORT +except AttributeError: + USHORT = ctypes.c_ushort + ###################### # jaraco.windows.error @@ -173,7 +178,7 @@ class SECURITY_DESCRIPTOR(ctypes.Structure): PACL Dacl; } SECURITY_DESCRIPTOR; """ - SECURITY_DESCRIPTOR_CONTROL = ctypes.wintypes.USHORT + SECURITY_DESCRIPTOR_CONTROL = USHORT REVISION = 1 _fields_ = [ diff --git a/paramiko/win_pageant.py b/paramiko/win_pageant.py index de1cd64..a7aea87 100644 --- a/paramiko/win_pageant.py +++ b/paramiko/win_pageant.py @@ -23,11 +23,11 @@ Functions for communicating with Pageant, the basic windows ssh agent program. from __future__ import with_statement -import struct -import threading import array -import platform import ctypes.wintypes +import platform +import struct +import thread from . import _winapi @@ -74,7 +74,7 @@ def _query_pageant(msg): return None # create a name for the mmap - map_name = 'PageantRequest%08x' % threading.current_thread().ident + map_name = 'PageantRequest%08x' % thread.get_ident() pymap = _winapi.MemoryMap(map_name, _AGENT_MAX_MSGLEN, _winapi.get_security_attributes_for_user(), From b0c689d7c86d9c3c421f4289c038c11464002dbb Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Tue, 21 Jan 2014 00:13:22 +0200 Subject: [PATCH 3/6] Support Py2.5 to Py3.4 for thread identity (thanks @lndbrg) --- paramiko/win_pageant.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/paramiko/win_pageant.py b/paramiko/win_pageant.py index a7aea87..1c0bc98 100644 --- a/paramiko/win_pageant.py +++ b/paramiko/win_pageant.py @@ -28,6 +28,7 @@ import ctypes.wintypes import platform import struct import thread +import threading from . import _winapi @@ -38,6 +39,13 @@ _AGENT_MAX_MSGLEN = 8192 win32con_WM_COPYDATA = 74 +def get_thread_ident(): + try: # thread.get_ident() exists from Py2.5 to Py2.7. + return thread.get_ident() + except AttributeError: # threading.current_thread().ident exists from Py2.6 up to Py3.4. + return threading.current_thread().ident + + def _get_pageant_window_object(): return ctypes.windll.user32.FindWindowA('Pageant', 'Pageant') @@ -51,7 +59,10 @@ def can_talk_to_agent(): """ 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 @@ -61,7 +72,8 @@ class COPYDATASTRUCT(ctypes.Structure): ('num_data', ULONG_PTR), ('data_size', ctypes.wintypes.DWORD), ('data_loc', ctypes.c_void_p), - ] + ] + def _query_pageant(msg): """ @@ -74,7 +86,7 @@ def _query_pageant(msg): return None # create a name for the mmap - map_name = 'PageantRequest%08x' % thread.get_ident() + map_name = 'PageantRequest%08x' % get_thread_ident() pymap = _winapi.MemoryMap(map_name, _AGENT_MAX_MSGLEN, _winapi.get_security_attributes_for_user(), @@ -98,7 +110,8 @@ def _query_pageant(msg): return datalen + pymap.read(retlen) return None -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 From 39809dab310b50d781f247ebbc89cf863fb545d3 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Tue, 21 Jan 2014 08:37:37 +0200 Subject: [PATCH 4/6] Try Py2.5 compatibility as last fallback for thread identity. --- paramiko/win_pageant.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/paramiko/win_pageant.py b/paramiko/win_pageant.py index 1c0bc98..2f6db4f 100644 --- a/paramiko/win_pageant.py +++ b/paramiko/win_pageant.py @@ -40,10 +40,12 @@ win32con_WM_COPYDATA = 74 def get_thread_ident(): - try: # thread.get_ident() exists from Py2.5 to Py2.7. - return thread.get_ident() - except AttributeError: # threading.current_thread().ident exists from Py2.6 up to Py3.4. + # thread.get_ident() exists from Py2.5 to Py2.7. + # threading.current_thread().ident exists from Py2.6 up to Py3.4. + try: return threading.current_thread().ident + except AttributeError: + return thread.get_ident() def _get_pageant_window_object(): From 2621db122dddc0ade86db22b7b789143db600c8f Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Tue, 21 Jan 2014 13:49:18 -0800 Subject: [PATCH 5/6] Add NEWS entry re #193 and friends --- NEWS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/NEWS b/NEWS index 2b48ba6..f66a014 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,13 @@ Issues noted as "Fabric #NN" can be found at https://github.com/fabric/fabric/. Releases ======== +v1.10.6 (21st Jan 2014) +----------------------- + +* #193 (and its attentant PRs #230 & #253): Fix SSH agent problems present on + Windows. Thanks to David Hobbs for initial report and to Aarni Koskela & Olle + Lundberg for the patches. + v1.10.5 (8th Jan 2014) ---------------------- From a7ea04842eb178fa24471914fbaa6d38ec35b78d Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Tue, 21 Jan 2014 13:51:09 -0800 Subject: [PATCH 6/6] Clean up thread ident import/exec a bit. --- paramiko/win_pageant.py | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/paramiko/win_pageant.py b/paramiko/win_pageant.py index 2f6db4f..d588e81 100644 --- a/paramiko/win_pageant.py +++ b/paramiko/win_pageant.py @@ -27,11 +27,15 @@ import array import ctypes.wintypes import platform import struct -import thread -import threading + +try: + import _thread as thread # Python 3.x +except ImportError: + import thread # Python 2.5-2.7 from . import _winapi + _AGENT_COPYDATA_ID = 0x804e50ba _AGENT_MAX_MSGLEN = 8192 # Note: The WM_COPYDATA value is pulled from win32con, as a workaround @@ -39,15 +43,6 @@ _AGENT_MAX_MSGLEN = 8192 win32con_WM_COPYDATA = 74 -def get_thread_ident(): - # thread.get_ident() exists from Py2.5 to Py2.7. - # threading.current_thread().ident exists from Py2.6 up to Py3.4. - try: - return threading.current_thread().ident - except AttributeError: - return thread.get_ident() - - def _get_pageant_window_object(): return ctypes.windll.user32.FindWindowA('Pageant', 'Pageant') @@ -88,7 +83,7 @@ def _query_pageant(msg): return None # create a name for the mmap - map_name = 'PageantRequest%08x' % get_thread_ident() + map_name = 'PageantRequest%08x' % thread.get_ident() pymap = _winapi.MemoryMap(map_name, _AGENT_MAX_MSGLEN, _winapi.get_security_attributes_for_user(),