diff options
-rw-r--r-- | dev-requirements.txt | 2 | ||||
-rw-r--r-- | paramiko/__init__.py | 2 | ||||
-rw-r--r-- | paramiko/packet.py | 1 | ||||
-rw-r--r-- | paramiko/proxy.py | 33 | ||||
-rw-r--r-- | paramiko/transport.py | 17 | ||||
-rw-r--r-- | setup.py | 2 | ||||
-rw-r--r-- | sites/www/changelog.rst | 31 |
7 files changed, 69 insertions, 19 deletions
diff --git a/dev-requirements.txt b/dev-requirements.txt index 26d7aac3..e4dd942d 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,3 +1,5 @@ +# Older junk +tox>=1.4,<1.5 # For newer tasks like building Sphinx docs. # NOTE: Requires Python >=2.6 invoke>=0.7.0 diff --git a/paramiko/__init__.py b/paramiko/__init__.py index f081de21..ada1fbd8 100644 --- a/paramiko/__init__.py +++ b/paramiko/__init__.py @@ -23,7 +23,7 @@ if sys.version_info < (2, 5): __author__ = "Jeff Forcier <jeff@bitprophet.org>" -__version__ = "1.10.6" +__version__ = "1.11.4" __version_info__ = tuple([ int(d) for d in __version__.split(".") ]) __license__ = "GNU Lesser General Public License (LGPL)" diff --git a/paramiko/packet.py b/paramiko/packet.py index 397193cd..62cda219 100644 --- a/paramiko/packet.py +++ b/paramiko/packet.py @@ -152,7 +152,6 @@ class Packetizer (object): def close(self): self.__closed = True - self.__socket.close() def set_hexdump(self, hexdump): self.__dump_packets = hexdump diff --git a/paramiko/proxy.py b/paramiko/proxy.py index 30d596ba..10f0728f 100644 --- a/paramiko/proxy.py +++ b/paramiko/proxy.py @@ -17,10 +17,13 @@ # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +from datetime import datetime import os from shlex import split as shlsplit import signal from subprocess import Popen, PIPE +from select import select +import socket from paramiko.ssh_exception import ProxyCommandFailure @@ -44,6 +47,8 @@ class ProxyCommand(object): """ self.cmd = shlsplit(command_line) self.process = Popen(self.cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE) + self.timeout = None + self.buffer = [] def send(self, content): """ @@ -59,7 +64,7 @@ class ProxyCommand(object): # died and we can't proceed. The best option here is to # raise an exception informing the user that the informed # ProxyCommand is not working. - raise BadProxyCommand(' '.join(self.cmd), e.strerror) + raise ProxyCommandFailure(' '.join(self.cmd), e.strerror) return len(content) def recv(self, size): @@ -71,14 +76,30 @@ class ProxyCommand(object): :return: the length of the read content, as an `int` """ try: - return os.read(self.process.stdout.fileno(), size) + start = datetime.now() + while len(self.buffer) < size: + if self.timeout is not None: + elapsed = (datetime.now() - start).microseconds + timeout = self.timeout * 1000 * 1000 # to microseconds + if elapsed >= timeout: + raise socket.timeout() + r, w, x = select([self.process.stdout], [], [], 0.0) + if r and r[0] == self.process.stdout: + b = os.read(self.process.stdout.fileno(), 1) + # Store in class-level buffer for persistence across + # timeouts; this makes us act more like a real socket + # (where timeouts don't actually drop data.) + self.buffer.append(b) + result = ''.join(self.buffer) + self.buffer = [] + return result + except socket.timeout: + raise # socket.timeout is a subclass of IOError except IOError, e: - raise BadProxyCommand(' '.join(self.cmd), e.strerror) + raise ProxyCommandFailure(' '.join(self.cmd), e.strerror) def close(self): os.kill(self.process.pid, signal.SIGTERM) def settimeout(self, timeout): - # Timeouts are meaningless for this implementation, but are part of the - # spec, so must be present. - pass + self.timeout = timeout diff --git a/paramiko/transport.py b/paramiko/transport.py index dfb3df81..6f3e3f4b 100644 --- a/paramiko/transport.py +++ b/paramiko/transport.py @@ -277,7 +277,6 @@ class Transport (threading.Thread): .. versionadded:: 1.5.3 """ - self.sock.close() self.close() def get_security_options(self): @@ -487,11 +486,10 @@ class Transport (threading.Thread): """ if not self.active: return - self.active = False - self.packetizer.close() - self.join() + self.stop_thread() for chan in self._channels.values(): chan._unlink() + self.sock.close() def get_remote_server_key(self): """ @@ -1239,6 +1237,8 @@ class Transport (threading.Thread): def stop_thread(self): self.active = False self.packetizer.close() + while self.isAlive(): + self.join(10) ### internals... @@ -1387,10 +1387,6 @@ class Transport (threading.Thread): # containers. Random.atfork() - # Hold reference to 'sys' so we can test sys.modules to detect - # interpreter shutdown. - self.sys = sys - # active=True occurs before the thread is launched, to avoid a race _active_threads.append(self) if self.server_mode: @@ -1460,7 +1456,10 @@ class Transport (threading.Thread): self.saved_exception = e except socket.error, e: if type(e.args) is tuple: - emsg = '%s (%d)' % (e.args[1], e.args[0]) + if e.args: + emsg = '%s (%d)' % (e.args[1], e.args[0]) + else: # empty tuple, e.g. socket.timeout + emsg = str(e) or repr(e) else: emsg = e.args self._log(ERROR, 'Socket exception: ' + emsg) @@ -52,7 +52,7 @@ if sys.platform == 'darwin': setup(name = "paramiko", - version = "1.10.6", + version = "1.11.4", description = "SSH2 protocol library", author = "Jeff Forcier", author_email = "jeff@bitprophet.org", diff --git a/sites/www/changelog.rst b/sites/www/changelog.rst index fee5a962..19383cdc 100644 --- a/sites/www/changelog.rst +++ b/sites/www/changelog.rst @@ -9,18 +9,31 @@ Changelog protect against `timing-based attacks <http://codahale.com/a-lesson-in-timing-attacks/>`_. Thanks to Alex Gaynor for the patch. +* :release:`1.11.4 <2014-02-14>` * :release:`1.10.6 <2014-02-14>` +* :bug:`252` (`Fabric #1020 <https://github.com/fabric/fabric/issues/1020>`_) + Enhanced the implementation of ``ProxyCommand`` to avoid a deadlock/hang + condition that frequently occurs at ``Transport`` shutdown time. Thanks to + Mateusz Kobos, Matthijs van der Vleuten and Guillaume Zitta for the original + reports and to Marius Gedminas for helping test nontrivial use cases. +* :bug:`268` Fix some missed renames of ``ProxyCommand`` related error classes. + Thanks to Marius Gedminas for catch & patch. * :bug:`34` (PR :issue:`35`) Fix SFTP prefetching incompatibility with some SFTP servers regarding request/response ordering. Thanks to Richard - Kettlewell for catch & patch. + Kettlewell. * :bug:`193` (and its attentant PRs :issue:`230` & :issue:`253`) Fix SSH agent problems present on Windows. Thanks to David Hobbs for initial report and to Aarni Koskela & Olle Lundberg for the patches. +* :release:`1.11.3 <2014-01-08>` * :release:`1.10.5 <2014-01-08>` * :bug:`176` Fix AttributeError bugs in known_hosts file (re)loading. Thanks to Nathan Scowcroft for the patch & Martin Blumenstingl for the initial test case. +* :release:`1.11.2 <2013-09-27>` * :release:`1.10.4 <2013-09-27>` +* :bug:`156 (1.11+)` Fix potential deadlock condition when using Channel + objects as sockets (e.g. when using SSH gatewaying). Thanks to Steven Noonan + and Frank Arnold for catch & patch. * :bug:`179` Fix a missing variable causing errors when an ssh_config file has a non-default AddressFamily set. Thanks to Ed Marshall & Tomaz Muraus for catch & patch. @@ -28,6 +41,7 @@ Changelog Buchanan for catch & Dave Foster for patch. * :bug:`199` Typo fix in the license header cross-project. Thanks to Armin Ronacher for catch & patch. +* :release:`1.11.1 <2013-09-20>` * :release:`1.10.3 <2013-09-20>` * :bug:`162` Clean up HMAC module import to avoid deadlocks in certain uses of SSHClient. Thanks to Gernot Hillier for the catch & suggested fix. @@ -35,7 +49,22 @@ Changelog Thanks to Jonathan Halcrow for catch & patch. * :bug:`168` Update config handling to properly handle multiple 'localforward' and 'remoteforward' keys. Thanks to Emre Yılmaz for the patch. +* :release:`1.11.0 <2013-07-26>` * :release:`1.10.2 <2013-07-26>` +* :bug:`98 major` On Windows, when interacting with the PuTTY PAgeant, Paramiko + now creates the shared memory map with explicit Security Attributes of the + user, which is the same technique employed by the canonical PuTTY library to + avoid permissions issues when Paramiko is running under a different UAC + context than the PuTTY Ageant process. Thanks to Jason R. Coombs for the + patch. +* :support:`100` Remove use of PyWin32 in ``win_pageant`` module. Module was + already dependent on ctypes for constructing appropriate structures and had + ctypes implementations of all functionality. Thanks to Jason R. Coombs for + the patch. +* :bug:`87 major` Ensure updates to ``known_hosts`` files account for any + updates to said files after Paramiko initially read them. (Includes related + fix to guard against duplicate entries during subsequent ``known_hosts`` + loads.) Thanks to ``@sunweaver`` for the contribution. * :bug:`153` (also :issue:`67`) Warn on parse failure when reading known_hosts file. Thanks to ``@glasserc`` for patch. * :bug:`146` Indentation fixes for readability. Thanks to Abhinav Upadhyay for |