From cb3008b402a6a411204d0dc060c2f85a548c1c7e Mon Sep 17 00:00:00 2001 From: Robey Pointer Date: Sat, 14 Jan 2006 22:30:08 -0800 Subject: [PATCH] [project @ robey@master-shake.local-20060115063008-4f68552398868788] fix a bunch of pychecker warnings, some of which were actual (but unlikely) bugs --- README | 3 ++ paramiko/ber.py | 5 +-- paramiko/channel.py | 49 +++++++++------------------ paramiko/dsskey.py | 10 +++++- paramiko/file.py | 3 ++ paramiko/kex_gex.py | 6 ++++ paramiko/message.py | 2 +- paramiko/packet.py | 10 +++--- paramiko/pipe.py | 6 ++-- paramiko/pkey.py | 8 ++--- paramiko/primes.py | 13 +++++--- paramiko/rsakey.py | 14 ++++++-- paramiko/sftp_attr.py | 50 ++++++++++++++-------------- paramiko/sftp_client.py | 10 +++--- paramiko/sftp_file.py | 12 +++++-- paramiko/sftp_handle.py | 20 ++++++----- paramiko/sftp_server.py | 12 +++---- paramiko/transport.py | 73 +++++++++++++++++++++++++---------------- paramiko/util.py | 10 +++--- 19 files changed, 182 insertions(+), 134 deletions(-) diff --git a/README b/README index 280a7ad..5608172 100644 --- a/README +++ b/README @@ -255,3 +255,6 @@ v1.0 JIGGLYPUFF key files, etc) local and remote port forwarding * SFTPClient.set_size +* remove @since that predate 1.0 +* put examples in examples/ folder + diff --git a/paramiko/ber.py b/paramiko/ber.py index 6a7823d..e8d6d62 100644 --- a/paramiko/ber.py +++ b/paramiko/ber.py @@ -16,7 +16,7 @@ # along with Paramiko; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -import struct + import util @@ -91,8 +91,9 @@ class BER(object): while True: x = b.decode_next() if x is None: - return out + break out.append(x) + return out decode_sequence = staticmethod(decode_sequence) def encode_tlv(self, ident, val): diff --git a/paramiko/channel.py b/paramiko/channel.py index 8a00233..ee2ec49 100644 --- a/paramiko/channel.py +++ b/paramiko/channel.py @@ -148,12 +148,7 @@ class Channel (object): m.add_string('') self.event.clear() self.transport._send_user_message(m) - while True: - self.event.wait(0.1) - if self.closed: - return False - if self.event.isSet(): - return True + return self._wait_for_event() def invoke_shell(self): """ @@ -180,12 +175,7 @@ class Channel (object): m.add_boolean(1) self.event.clear() self.transport._send_user_message(m) - while True: - self.event.wait(0.1) - if self.closed: - return False - if self.event.isSet(): - return True + return self._wait_for_event() def exec_command(self, command): """ @@ -212,12 +202,7 @@ class Channel (object): m.add_string(command) self.event.clear() self.transport._send_user_message(m) - while True: - self.event.wait(0.1) - if self.closed: - return False - if self.event.isSet(): - return True + return self._wait_for_event() def invoke_subsystem(self, subsystem): """ @@ -243,12 +228,7 @@ class Channel (object): m.add_string(subsystem) self.event.clear() self.transport._send_user_message(m) - while True: - self.event.wait(0.1) - if self.closed: - return False - if self.event.isSet(): - return True + return self._wait_for_event() def resize_pty(self, width=80, height=24): """ @@ -274,12 +254,7 @@ class Channel (object): m.add_int(0).add_int(0) self.event.clear() self.transport._send_user_message(m) - while True: - self.event.wait(0.1) - if self.closed: - return False - if self.event.isSet(): - return True + self._wait_for_event() def recv_exit_status(self): """ @@ -296,8 +271,9 @@ class Channel (object): """ while True: if self.closed or self.status_event.isSet(): - return self.exit_status + break self.status_event.wait(0.1) + return self.exit_status def send_exit_status(self, status): """ @@ -1027,6 +1003,15 @@ class Channel (object): def _log(self, level, msg): self.logger.log(level, msg) + def _wait_for_event(self): + while True: + self.event.wait(0.1) + if self.closed: + return False + if self.event.isSet(): + break + return True + def _set_closed(self): # you are holding the lock. self.closed = True @@ -1155,8 +1140,6 @@ class ChannelFile (BufferedFile): def _write(self, data): self.channel.sendall(data) return len(data) - - seek = BufferedFile.seek class ChannelStderrFile (ChannelFile): diff --git a/paramiko/dsskey.py b/paramiko/dsskey.py index 2b31372..dcb7411 100644 --- a/paramiko/dsskey.py +++ b/paramiko/dsskey.py @@ -36,6 +36,12 @@ class DSSKey (PKey): Representation of a DSS key which can be used to sign an verify SSH2 data. """ + + p = None + q = None + g = None + y = None + x = None def __init__(self, msg=None, data=None, filename=None, password=None, vals=None): if filename is not None: @@ -81,7 +87,7 @@ class DSSKey (PKey): return self.size def can_sign(self): - return hasattr(self, 'x') + return self.x is not None def sign_ssh_data(self, rpool, data): digest = SHA.new(data).digest() @@ -124,6 +130,8 @@ class DSSKey (PKey): return dss.verify(sigM, (sigR, sigS)) def write_private_key_file(self, filename, password=None): + if self.x is None: + raise SSHException('Not enough key information') keylist = [ 0, self.p, self.q, self.g, self.y, self.x ] try: b = BER() diff --git a/paramiko/file.py b/paramiko/file.py index c29e7c4..4378474 100644 --- a/paramiko/file.py +++ b/paramiko/file.py @@ -45,6 +45,7 @@ class BufferedFile (object): SEEK_END = 2 def __init__(self): + self.newlines = None self._flags = 0 self._bufsize = self._DEFAULT_BUFSIZE self._wbuffer = StringIO() @@ -55,6 +56,8 @@ class BufferedFile (object): # realpos - position according the OS # (these may be different because we buffer for line reading) self._pos = self._realpos = 0 + # size only matters for seekable files + self._size = 0 def __del__(self): self.close() diff --git a/paramiko/kex_gex.py b/paramiko/kex_gex.py index 994d76c..3e32210 100644 --- a/paramiko/kex_gex.py +++ b/paramiko/kex_gex.py @@ -43,6 +43,12 @@ class KexGex (object): def __init__(self, transport): self.transport = transport + self.p = None + self.q = None + self.g = None + self.x = None + self.e = None + self.f = None def start_kex(self): if self.transport.server_mode: diff --git a/paramiko/message.py b/paramiko/message.py index 1d75a01..b110700 100644 --- a/paramiko/message.py +++ b/paramiko/message.py @@ -285,7 +285,7 @@ class Message (object): elif type(i) is list: return self.add_list(i) else: - raise exception('Unknown type') + raise Exception('Unknown type') def add(self, *seq): """ diff --git a/paramiko/packet.py b/paramiko/packet.py index 277d68e..7e9afc7 100644 --- a/paramiko/packet.py +++ b/paramiko/packet.py @@ -219,7 +219,7 @@ class Packetizer (object): if n < 0: raise EOFError() if n == len(out): - return + break out = out[n:] return @@ -398,23 +398,24 @@ class Packetizer (object): x = self.__socket.recv(1) if len(x) == 0: raise EOFError() - return x + break if self.__closed: raise EOFError() now = time.time() if now - start >= timeout: raise socket.timeout() + return x def _read_timeout(self, timeout): if PY22: - return self._py22_read_timeout(n) + return self._py22_read_timeout(timeout) start = time.time() while True: try: x = self.__socket.recv(1) if len(x) == 0: raise EOFError() - return x + break except socket.timeout: pass if self.__closed: @@ -422,6 +423,7 @@ class Packetizer (object): now = time.time() if now - start >= timeout: raise socket.timeout() + return x def _build_packet(self, payload): # pad up at least 4 bytes, to nearest block-size (usually 8) diff --git a/paramiko/pipe.py b/paramiko/pipe.py index cc28f43..4048a14 100644 --- a/paramiko/pipe.py +++ b/paramiko/pipe.py @@ -28,8 +28,10 @@ import socket def make_pipe (): if sys.platform[:3] != 'win': - return PosixPipe() - return WindowsPipe() + p = PosixPipe() + else: + p = WindowsPipe() + return p class PosixPipe (object): diff --git a/paramiko/pkey.py b/paramiko/pkey.py index 75db8e5..b6baf80 100644 --- a/paramiko/pkey.py +++ b/paramiko/pkey.py @@ -173,7 +173,7 @@ class PKey (object): """ return False - def from_private_key_file(cl, filename, password=None): + def from_private_key_file(cls, filename, password=None): """ Create a key object by reading a private key file. If the private key is encrypted and C{password} is not C{None}, the given password @@ -197,7 +197,7 @@ class PKey (object): @since: fearow """ - key = cl(filename=filename, password=password) + key = cls(filename=filename, password=password) return key from_private_key_file = classmethod(from_private_key_file) @@ -216,7 +216,7 @@ class PKey (object): @since: fearow """ - raise exception('Not implemented in PKey') + raise Exception('Not implemented in PKey') def _read_private_key_file(self, tag, filename, password=None): """ @@ -265,7 +265,7 @@ class PKey (object): # if we trudged to the end of the file, just try to cope. try: data = base64.decodestring(''.join(lines[start:end])) - except binascii.Error, e: + except base64.binascii.Error, e: raise SSHException('base64 decoding error: ' + str(e)) if not headers.has_key('proc-type'): # unencryped: done diff --git a/paramiko/primes.py b/paramiko/primes.py index 3677394..fa0175d 100644 --- a/paramiko/primes.py +++ b/paramiko/primes.py @@ -23,6 +23,7 @@ Utility functions for dealing with primes. from Crypto.Util import number from paramiko import util +from paramiko.ssh_exception import SSHException def _generate_prime(bits, randpool): @@ -39,7 +40,8 @@ def _generate_prime(bits, randpool): while not number.isPrime(n): n += 2 if util.bit_length(n) == bits: - return n + break + return n def _roll_random(rpool, n): "returns a random # from 0 to N-1" @@ -59,7 +61,8 @@ def _roll_random(rpool, n): x = chr(ord(x[0]) & hbyte_mask) + x[1:] num = util.inflate_long(x, 1) if num < n: - return num + break + return num class ModulusPack (object): @@ -75,8 +78,8 @@ class ModulusPack (object): self.randpool = rpool def _parse_modulus(self, line): - timestamp, type, tests, tries, size, generator, modulus = line.split() - type = int(type) + timestamp, mod_type, tests, tries, size, generator, modulus = line.split() + mod_type = int(mod_type) tests = int(tests) tries = int(tries) size = int(size) @@ -87,7 +90,7 @@ class ModulusPack (object): # type 2 (meets basic structural requirements) # test 4 (more than just a small-prime sieve) # tries < 100 if test & 4 (at least 100 tries of miller-rabin) - if (type < 2) or (tests < 4) or ((tests & 4) and (tests < 8) and (tries < 100)): + if (mod_type < 2) or (tests < 4) or ((tests & 4) and (tests < 8) and (tries < 100)): self.discarded.append((modulus, 'does not meet basic requirements')) return if generator == 0: diff --git a/paramiko/rsakey.py b/paramiko/rsakey.py index 780ea1b..754e412 100644 --- a/paramiko/rsakey.py +++ b/paramiko/rsakey.py @@ -38,6 +38,12 @@ class RSAKey (PKey): data. """ + n = None + e = None + d = None + p = None + q = None + def __init__(self, msg=None, data=None, filename=None, password=None, vals=None): if filename is not None: self._from_private_key_file(filename, password) @@ -75,7 +81,7 @@ class RSAKey (PKey): return self.size def can_sign(self): - return hasattr(self, 'd') + return self.d is not None def sign_ssh_data(self, rpool, data): digest = SHA.new(data).digest() @@ -93,11 +99,13 @@ class RSAKey (PKey): # verify the signature by SHA'ing the data and encrypting it using the # public key. some wackiness ensues where we "pkcs1imify" the 20-byte # hash into a string as long as the RSA key. - hash = util.inflate_long(self._pkcs1imify(SHA.new(data).digest()), True) + hash_obj = util.inflate_long(self._pkcs1imify(SHA.new(data).digest()), True) rsa = RSA.construct((long(self.n), long(self.e))) - return rsa.verify(hash, (sig,)) + return rsa.verify(hash_obj, (sig,)) def write_private_key_file(self, filename, password=None): + if (self.p is None) or (self.q is None): + raise SSHException('Not enough key info to write private key file') keylist = [ 0, self.n, self.e, self.d, self.p, self.q, self.d % (self.p - 1), self.d % (self.q - 1), util.mod_inverse(self.q, self.p) ] diff --git a/paramiko/sftp_attr.py b/paramiko/sftp_attr.py index eae7c99..0548dcd 100644 --- a/paramiko/sftp_attr.py +++ b/paramiko/sftp_attr.py @@ -51,6 +51,12 @@ class SFTPAttributes (object): Create a new (empty) SFTPAttributes object. All fields will be empty. """ self._flags = 0 + self.st_size = -1 + self.st_uid = -1 + self.st_gid = -1 + self.st_mode = 0 + self.st_atime = 0 + self.st_mtime = 0 self.attr = {} def from_stat(cls, obj, filename=None): @@ -114,13 +120,13 @@ class SFTPAttributes (object): def _pack(self, msg): self._flags = 0 - if hasattr(self, 'st_size'): + if self.st_size >= 0: self._flags |= self.FLAG_SIZE - if hasattr(self, 'st_uid') or hasattr(self, 'st_gid'): + if (self.st_uid >= 0) or (self.st_gid >= 0): self._flags |= self.FLAG_UIDGID - if hasattr(self, 'st_mode'): + if self.st_mode != 0: self._flags |= self.FLAG_PERMISSIONS - if hasattr(self, 'st_atime') or hasattr(self, 'st_mtime'): + if (self.st_atime > 0) or (self.st_mtime > 0): self._flags |= self.FLAG_AMTIME if len(self.attr) > 0: self._flags |= self.FLAG_EXTENDED @@ -128,13 +134,13 @@ class SFTPAttributes (object): if self._flags & self.FLAG_SIZE: msg.add_int64(self.st_size) if self._flags & self.FLAG_UIDGID: - msg.add_int(getattr(self, 'st_uid', 0)) - msg.add_int(getattr(self, 'st_gid', 0)) + msg.add_int(self.st_uid) + msg.add_int(self.st_gid) if self._flags & self.FLAG_PERMISSIONS: msg.add_int(self.st_mode) if self._flags & self.FLAG_AMTIME: - msg.add_int(getattr(self, 'st_atime', 0)) - msg.add_int(getattr(self, 'st_mtime', 0)) + msg.add_int(self.st_atime) + msg.add_int(self.st_mtime) if self._flags & self.FLAG_EXTENDED: msg.add_int(len(self.attr)) for key, val in self.attr.iteritems(): @@ -144,15 +150,14 @@ class SFTPAttributes (object): def _debug_str(self): out = '[ ' - if hasattr(self, 'st_size'): + if self.st_size >= 0: out += 'size=%d ' % self.st_size - if hasattr(self, 'st_uid') or hasattr(self, 'st_gid'): - out += 'uid=%d gid=%d ' % (getattr(self, 'st_uid', 0), getattr(self, 'st_gid', 0)) - if hasattr(self, 'st_mode'): + if (self.st_uid >= 0) or (self.st_gid >= 0): + out += 'uid=%d gid=%d ' % (self.st_uid, self.st_gid) + if self.st_mode != 0: out += 'mode=' + oct(self.st_mode) + ' ' - if hasattr(self, 'st_atime') or hasattr(self, 'st_mtime'): - out += 'atime=%d mtime=%d ' % (getattr(self, 'st_atime', 0), - getattr(self, 'st_mtime', 0)) + if (self.st_atime > 0) or (self.st_mtime > 0): + out += 'atime=%d mtime=%d ' % (self.st_atime, self.st_mtime) for k, v in self.attr.iteritems(): out += '"%s"=%r ' % (str(k), v) out += ']' @@ -171,7 +176,7 @@ class SFTPAttributes (object): def __str__(self): "create a unix-style long description of the file (like ls -l)" - if hasattr(self, 'st_mode'): + if self.st_mode != 0: kind = stat.S_IFMT(self.st_mode) if kind == stat.S_IFIFO: ks = 'p' @@ -194,15 +199,12 @@ class SFTPAttributes (object): ks += self._rwx(self.st_mode & 7, self.st_mode & stat.S_ISVTX, True) else: ks = '?---------' - uid = getattr(self, 'st_uid', -1) - gid = getattr(self, 'st_gid', -1) - size = getattr(self, 'st_size', -1) - mtime = getattr(self, 'st_mtime', 0) # compute display date - if abs(time.time() - mtime) > 15552000: + if abs(time.time() - self.st_mtime) > 15552000: # (15552000 = 6 months) - datestr = time.strftime('%d %b %Y', time.localtime(mtime)) + datestr = time.strftime('%d %b %Y', time.localtime(self.st_mtime)) else: - datestr = time.strftime('%d %b %H:%M', time.localtime(mtime)) + datestr = time.strftime('%d %b %H:%M', time.localtime(self.st_mtime)) filename = getattr(self, 'filename', '?') - return '%s 1 %-8d %-8d %8d %-12s %s' % (ks, uid, gid, size, datestr, filename) + return '%s 1 %-8d %-8d %8d %-12s %s' % (ks, self.st_uid, self.st_gid, + self.st_size, datestr, filename) diff --git a/paramiko/sftp_client.py b/paramiko/sftp_client.py index 2fe89e9..ba37455 100644 --- a/paramiko/sftp_client.py +++ b/paramiko/sftp_client.py @@ -23,6 +23,7 @@ Client-mode SFTP support. import errno import os import threading +import time import weakref from paramiko.sftp import * from paramiko.sftp_attr import SFTPAttributes @@ -74,7 +75,7 @@ class SFTPClient (BaseSFTP): def __del__(self): self.close() - def from_transport(selfclass, t): + def from_transport(cls, t): """ Create an SFTP client channel from an open L{Transport}. @@ -89,7 +90,7 @@ class SFTPClient (BaseSFTP): return None if not chan.invoke_subsystem('sftp'): raise SFTPError('Failed to invoke sftp subsystem') - return selfclass(chan) + return cls(chan) from_transport = classmethod(from_transport) def close(self): @@ -560,7 +561,7 @@ class SFTPClient (BaseSFTP): self._log(DEBUG, 'Unexpected response #%d' % (num,)) if waitfor is None: # just doing a single check - return + break continue fileobj = self._expecting[num] del self._expecting[num] @@ -573,7 +574,8 @@ class SFTPClient (BaseSFTP): fileobj._async_response(t, msg) if waitfor is None: # just doing a single check - return + break + return (None, None) def _finish_responses(self, fileobj): while fileobj in self._expecting.values(): diff --git a/paramiko/sftp_file.py b/paramiko/sftp_file.py index f224f02..bdc60c7 100644 --- a/paramiko/sftp_file.py +++ b/paramiko/sftp_file.py @@ -43,12 +43,18 @@ class SFTPFile (BufferedFile): BufferedFile._set_mode(self, mode, bufsize) self.pipelined = False self._prefetching = False + self._prefetch_so_far = 0 + self._prefetch_size = 0 + self._prefetch_data = {} self._saved_exception = None def __del__(self): - self.close(_async=True) + self._close(async=True) + + def close(self): + self._close(async=False) - def close(self, _async=False): + def _close(self, async=False): # We allow double-close without signaling an error, because real # Python file objects do. However, we must protect against actually # sending multiple CMD_CLOSE packets, because after we close our @@ -62,7 +68,7 @@ class SFTPFile (BufferedFile): self.sftp._finish_responses(self) BufferedFile.close(self) try: - if _async: + if async: # GC'd file handle could be called from an arbitrary thread -- don't wait for a response self.sftp._async_request(type(None), CMD_CLOSE, self.handle) else: diff --git a/paramiko/sftp_handle.py b/paramiko/sftp_handle.py index e1d93e9..11a72c2 100644 --- a/paramiko/sftp_handle.py +++ b/paramiko/sftp_handle.py @@ -81,15 +81,16 @@ class SFTPHandle (object): @return: data read from the file, or an SFTP error code. @rtype: str """ - if not hasattr(self, 'readfile') or (self.readfile is None): + readfile = getattr(self, 'readfile', None) + if readfile is None: return SFTP_OP_UNSUPPORTED try: if self.__tell is None: - self.__tell = self.readfile.tell() + self.__tell = readfile.tell() if offset != self.__tell: - self.readfile.seek(offset) + readfile.seek(offset) self.__tell = offset - data = self.readfile.read(length) + data = readfile.read(length) except IOError, e: self.__tell = None return SFTPServer.convert_errno(e.errno) @@ -116,16 +117,17 @@ class SFTPHandle (object): @type data: str @return: an SFTP error code like L{SFTP_OK}. """ - if not hasattr(self, 'writefile') or (self.writefile is None): + writefile = getattr(self, 'writefile', None) + if writefile is None: return SFTP_OP_UNSUPPORTED try: if self.__tell is None: - self.__tell = self.writefile.tell() + self.__tell = writefile.tell() if offset != self.__tell: - self.writefile.seek(offset) + writefile.seek(offset) self.__tell = offset - self.writefile.write(data) - self.writefile.flush() + writefile.write(data) + writefile.flush() except IOError, e: self.__tell = None return SFTPServer.convert_errno(e.errno) diff --git a/paramiko/sftp_server.py b/paramiko/sftp_server.py index 7b63483..253cffb 100644 --- a/paramiko/sftp_server.py +++ b/paramiko/sftp_server.py @@ -246,29 +246,29 @@ class SFTPServer (BaseSFTP, SubsystemHandler): self._send_status(request_number, SFTP_FAILURE, 'Block size too small') return - sum = '' + sum_out = '' offset = start while offset < start + length: blocklen = min(block_size, start + length - offset) # don't try to read more than about 64KB at a time chunklen = min(blocklen, 65536) count = 0 - hash = alg.new() + hash_obj = alg.new() while count < blocklen: data = f.read(offset, chunklen) if not type(data) is str: self._send_status(request_number, data, 'Unable to hash file') return - hash.update(data) + hash_obj.update(data) count += len(data) offset += count - sum += hash.digest() + sum_out += hash_obj.digest() msg = Message() msg.add_int(request_number) msg.add_string('check-file') msg.add_string(algname) - msg.add_bytes(sum) + msg.add_bytes(sum_out) self._send_packet(CMD_EXTENDED_REPLY, str(msg)) def _convert_pflags(self, pflags): @@ -412,7 +412,7 @@ class SFTPServer (BaseSFTP, SubsystemHandler): if tag == 'check-file': self._check_file(request_number, msg) else: - send._send_status(request_number, SFTP_OP_UNSUPPORTED) + self._send_status(request_number, SFTP_OP_UNSUPPORTED) else: self._send_status(request_number, SFTP_OP_UNSUPPORTED) diff --git a/paramiko/transport.py b/paramiko/transport.py index 8714a96..abc1ea9 100644 --- a/paramiko/transport.py +++ b/paramiko/transport.py @@ -30,19 +30,20 @@ import time import weakref from paramiko import util +from paramiko.auth_handler import AuthHandler +from paramiko.channel import Channel from paramiko.common import * from paramiko.compress import ZlibCompressor, ZlibDecompressor -from paramiko.ssh_exception import SSHException, BadAuthenticationType -from paramiko.message import Message -from paramiko.channel import Channel -from paramiko.sftp_client import SFTPClient -from paramiko.packet import Packetizer, NeedRekeyException -from paramiko.rsakey import RSAKey from paramiko.dsskey import DSSKey -from paramiko.kex_group1 import KexGroup1 from paramiko.kex_gex import KexGex +from paramiko.kex_group1 import KexGroup1 +from paramiko.message import Message +from paramiko.packet import Packetizer, NeedRekeyException from paramiko.primes import ModulusPack -from paramiko.auth_handler import AuthHandler +from paramiko.rsakey import RSAKey +from paramiko.server import ServerInterface +from paramiko.sftp_client import SFTPClient +from paramiko.ssh_exception import SSHException, BadAuthenticationType # these come from PyCrypt # http://www.amk.ca/python/writing/pycrypt/ @@ -110,7 +111,8 @@ class SecurityOptions (object): if type(x) is not tuple: raise TypeError('expected tuple or list') possible = getattr(self._transport, orig).keys() - if len(filter(lambda n: n not in possible, x)) > 0: + forbidden = filter(lambda n: n not in possible, x) + if len(forbidden) > 0: raise ValueError('unknown cipher') setattr(self._transport, name, x) @@ -245,25 +247,39 @@ class Transport (threading.Thread): self.sock.settimeout(0.1) except AttributeError: pass + # negotiated crypto parameters self.packetizer = Packetizer(sock) self.local_version = 'SSH-' + self._PROTO_ID + '-' + self._CLIENT_ID self.remote_version = '' self.local_cipher = self.remote_cipher = '' self.local_kex_init = self.remote_kex_init = None + self.local_mac = self.remote_mac = None + self.local_compression = self.remote_compression = None self.session_id = None - # /negotiated crypto parameters - self.expected_packet = 0 + self.host_key_type = None + self.host_key = None + + # state used during negotiation + self.kex_engine = None + self.H = None + self.K = None + self.active = False self.initial_kex_done = False self.in_kex = False + self.authenticated = False + self.expected_packet = 0 self.lock = threading.Lock() # synchronization (always higher level than write_lock) + + # tracking open channels self.channels = weakref.WeakValueDictionary() # (id -> Channel) self.channel_events = { } # (id -> Event) self.channels_seen = { } # (id -> True) self.channel_counter = 1 self.window_size = 65536 self.max_packet_size = 34816 + self.saved_exception = None self.clear_to_send = threading.Event() self.clear_to_send_lock = threading.Lock() @@ -271,9 +287,9 @@ class Transport (threading.Thread): self.logger = util.get_logger(self.log_name) self.packetizer.set_log(self.logger) self.auth_handler = None - self.authenticated = False - # user-defined event callbacks: - self.completion_event = None + self.global_response = None # response Message from an arbitrary global request + self.completion_event = None # user-defined event callbacks + # server mode: self.server_mode = False self.server_object = None @@ -993,7 +1009,7 @@ class Transport (threading.Thread): return self.auth_handler.wait_for_response(my_event) except BadAuthenticationType, x: # if password auth isn't allowed, but keyboard-interactive *is*, try to fudge it - if not fallback or not 'keyboard-interactive' in x.allowed_types: + if not fallback or ('keyboard-interactive' not in x.allowed_types): raise try: def handler(title, instructions, fields): @@ -1010,6 +1026,7 @@ class Transport (threading.Thread): except SSHException, ignored: # attempt failed; just raise the original exception raise x + return None def auth_publickey(self, username, key, event=None): """ @@ -1262,9 +1279,9 @@ class Transport (threading.Thread): m.add_mpint(self.K) m.add_bytes(self.H) m.add_bytes(sofar) - hash = SHA.new(str(m)).digest() - out += hash - sofar += hash + digest = SHA.new(str(m)).digest() + out += digest + sofar += digest return out[:nbytes] def _get_cipher(self, name, key, iv): @@ -1394,24 +1411,24 @@ class Transport (threading.Thread): else: timeout = 2 try: - buffer = self.packetizer.readline(timeout) + buf = self.packetizer.readline(timeout) except Exception, x: raise SSHException('Error reading SSH protocol banner' + str(x)) - if buffer[:4] == 'SSH-': + if buf[:4] == 'SSH-': break - self._log(DEBUG, 'Banner: ' + buffer) - if buffer[:4] != 'SSH-': - raise SSHException('Indecipherable protocol version "' + buffer + '"') + self._log(DEBUG, 'Banner: ' + buf) + if buf[:4] != 'SSH-': + raise SSHException('Indecipherable protocol version "' + buf + '"') # save this server version string for later - self.remote_version = buffer + self.remote_version = buf # pull off any attached comment comment = '' - i = string.find(buffer, ' ') + i = string.find(buf, ' ') if i >= 0: - comment = buffer[i+1:] - buffer = buffer[:i] + comment = buf[i+1:] + buf = buf[:i] # parse out version string and make sure it matches - segs = buffer.split('-', 2) + segs = buf.split('-', 2) if len(segs) < 3: raise SSHException('Invalid SSH banner') version = segs[1] diff --git a/paramiko/util.py b/paramiko/util.py index abab825..77eee3f 100644 --- a/paramiko/util.py +++ b/paramiko/util.py @@ -168,12 +168,12 @@ def generate_key_bytes(hashclass, salt, key, nbytes): if len(salt) > 8: salt = salt[:8] while nbytes > 0: - hash = hashclass.new() + hash_obj = hashclass.new() if len(digest) > 0: - hash.update(digest) - hash.update(key) - hash.update(salt) - digest = hash.digest() + hash_obj.update(digest) + hash_obj.update(key) + hash_obj.update(salt) + digest = hash_obj.digest() size = min(nbytes, len(digest)) keydata += digest[:size] nbytes -= size