Merge remote-tracking branch 'scottkmaxwell/python3-with-import-fix' into python3

This commit is contained in:
Jeff Forcier 2014-03-13 11:19:04 -07:00
commit ba55eea38d
43 changed files with 384 additions and 474 deletions

View File

@ -29,12 +29,12 @@ import time
import tempfile import tempfile
import stat import stat
from select import select from select import select
from paramiko.common import asbytes, io_sleep
from paramiko.py3compat import byte_chr
from paramiko.ssh_exception import SSHException from paramiko.ssh_exception import SSHException
from paramiko.message import Message from paramiko.message import Message
from paramiko.pkey import PKey from paramiko.pkey import PKey
from paramiko.channel import Channel
from paramiko.common import *
from paramiko.util import retry_on_signal from paramiko.util import retry_on_signal
cSSH2_AGENTC_REQUEST_IDENTITIES = byte_chr(11) cSSH2_AGENTC_REQUEST_IDENTITIES = byte_chr(11)
@ -43,7 +43,6 @@ cSSH2_AGENTC_SIGN_REQUEST = byte_chr(13)
SSH2_AGENT_SIGN_RESPONSE = 14 SSH2_AGENT_SIGN_RESPONSE = 14
class AgentSSH(object): class AgentSSH(object):
def __init__(self): def __init__(self):
self._conn = None self._conn = None
@ -107,7 +106,7 @@ class AgentProxyThread(threading.Thread):
def run(self): def run(self):
try: try:
(r,addr) = self.get_connection() (r, addr) = self.get_connection()
self.__inr = r self.__inr = r
self.__addr = addr self.__addr = addr
self._agent.connect() self._agent.connect()
@ -163,11 +162,10 @@ class AgentLocalProxy(AgentProxyThread):
try: try:
conn.bind(self._agent._get_filename()) conn.bind(self._agent._get_filename())
conn.listen(1) conn.listen(1)
(r,addr) = conn.accept() (r, addr) = conn.accept()
return (r, addr) return r, addr
except: except:
raise raise
return None
class AgentRemoteProxy(AgentProxyThread): class AgentRemoteProxy(AgentProxyThread):
@ -179,7 +177,7 @@ class AgentRemoteProxy(AgentProxyThread):
self.__chan = chan self.__chan = chan
def get_connection(self): def get_connection(self):
return (self.__chan, None) return self.__chan, None
class AgentClientProxy(object): class AgentClientProxy(object):
@ -280,9 +278,7 @@ class AgentServerProxy(AgentSSH):
:return: :return:
a dict containing the ``SSH_AUTH_SOCK`` environnement variables a dict containing the ``SSH_AUTH_SOCK`` environnement variables
""" """
env = {} return {'SSH_AUTH_SOCK': self._get_filename()}
env['SSH_AUTH_SOCK'] = self._get_filename()
return env
def _get_filename(self): def _get_filename(self):
return self._file return self._file

View File

@ -20,15 +20,18 @@
`.AuthHandler` `.AuthHandler`
""" """
import threading
import weakref import weakref
from paramiko.common import cMSG_SERVICE_REQUEST, cMSG_DISCONNECT, \
DISCONNECT_SERVICE_NOT_AVAILABLE, DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, \
cMSG_USERAUTH_REQUEST, cMSG_SERVICE_ACCEPT, DEBUG, AUTH_SUCCESSFUL, INFO, \
cMSG_USERAUTH_SUCCESS, cMSG_USERAUTH_FAILURE, AUTH_PARTIALLY_SUCCESSFUL, \
cMSG_USERAUTH_INFO_REQUEST, WARNING, AUTH_FAILED, cMSG_USERAUTH_PK_OK, \
cMSG_USERAUTH_INFO_RESPONSE, MSG_SERVICE_REQUEST, MSG_SERVICE_ACCEPT, \
MSG_USERAUTH_REQUEST, MSG_USERAUTH_SUCCESS, MSG_USERAUTH_FAILURE, \
MSG_USERAUTH_BANNER, MSG_USERAUTH_INFO_REQUEST, MSG_USERAUTH_INFO_RESPONSE
# this helps freezing utils
import encodings.utf_8
from paramiko.common import *
from paramiko import util
from paramiko.message import Message from paramiko.message import Message
from paramiko.py3compat import bytestring
from paramiko.ssh_exception import SSHException, AuthenticationException, \ from paramiko.ssh_exception import SSHException, AuthenticationException, \
BadAuthenticationType, PartialAuthentication BadAuthenticationType, PartialAuthentication
from paramiko.server import InteractiveQuery from paramiko.server import InteractiveQuery
@ -114,10 +117,8 @@ class AuthHandler (object):
if self.auth_event is not None: if self.auth_event is not None:
self.auth_event.set() self.auth_event.set()
### internals... ### internals...
def _request_auth(self): def _request_auth(self):
m = Message() m = Message()
m.add_byte(cMSG_SERVICE_REQUEST) m.add_byte(cMSG_SERVICE_REQUEST)
@ -149,7 +150,7 @@ class AuthHandler (object):
m.add_string(username) m.add_string(username)
m.add_string(service) m.add_string(service)
m.add_string('publickey') m.add_string('publickey')
m.add_boolean(1) m.add_boolean(True)
m.add_string(key.get_name()) m.add_string(key.get_name())
m.add_string(key) m.add_string(key)
return m.asbytes() return m.asbytes()
@ -230,9 +231,9 @@ class AuthHandler (object):
m.add_byte(cMSG_USERAUTH_FAILURE) m.add_byte(cMSG_USERAUTH_FAILURE)
m.add_string(self.transport.server_object.get_allowed_auths(username)) m.add_string(self.transport.server_object.get_allowed_auths(username))
if result == AUTH_PARTIALLY_SUCCESSFUL: if result == AUTH_PARTIALLY_SUCCESSFUL:
m.add_boolean(1) m.add_boolean(True)
else: else:
m.add_boolean(0) m.add_boolean(False)
self.auth_fail_count += 1 self.auth_fail_count += 1
self.transport._send_message(m) self.transport._send_message(m)
if self.auth_fail_count >= 10: if self.auth_fail_count >= 10:
@ -259,7 +260,7 @@ class AuthHandler (object):
m = Message() m = Message()
m.add_byte(cMSG_USERAUTH_FAILURE) m.add_byte(cMSG_USERAUTH_FAILURE)
m.add_string('none') m.add_string('none')
m.add_boolean(0) m.add_boolean(False)
self.transport._send_message(m) self.transport._send_message(m)
return return
if self.authenticated: if self.authenticated:
@ -351,7 +352,7 @@ class AuthHandler (object):
self.transport._log(INFO, 'Authentication (%s) successful!' % self.auth_method) self.transport._log(INFO, 'Authentication (%s) successful!' % self.auth_method)
self.authenticated = True self.authenticated = True
self.transport._auth_trigger() self.transport._auth_trigger()
if self.auth_event != None: if self.auth_event is not None:
self.auth_event.set() self.auth_event.set()
def _parse_userauth_failure(self, m): def _parse_userauth_failure(self, m):
@ -369,7 +370,7 @@ class AuthHandler (object):
self.transport._log(INFO, 'Authentication (%s) failed.' % self.auth_method) self.transport._log(INFO, 'Authentication (%s) failed.' % self.auth_method)
self.authenticated = False self.authenticated = False
self.username = None self.username = None
if self.auth_event != None: if self.auth_event is not None:
self.auth_event.set() self.auth_event.set()
def _parse_userauth_banner(self, m): def _parse_userauth_banner(self, m):
@ -411,7 +412,6 @@ class AuthHandler (object):
self._interactive_query(result) self._interactive_query(result)
return return
self._send_auth_result(self.auth_username, 'keyboard-interactive', result) self._send_auth_result(self.auth_username, 'keyboard-interactive', result)
_handler_table = { _handler_table = {
MSG_SERVICE_REQUEST: _parse_service_request, MSG_SERVICE_REQUEST: _parse_service_request,
@ -423,4 +423,3 @@ class AuthHandler (object):
MSG_USERAUTH_INFO_REQUEST: _parse_userauth_info_request, MSG_USERAUTH_INFO_REQUEST: _parse_userauth_info_request,
MSG_USERAUTH_INFO_RESPONSE: _parse_userauth_info_response, MSG_USERAUTH_INFO_RESPONSE: _parse_userauth_info_response,
} }

View File

@ -15,10 +15,10 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Paramiko; if not, write to the Free Software Foundation, Inc., # along with Paramiko; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
from paramiko.common import max_byte, zero_byte
from paramiko.py3compat import b, byte_ord, byte_chr, long
import paramiko.util as util import paramiko.util as util
from paramiko.common import *
class BERException (Exception): class BERException (Exception):
@ -71,12 +71,12 @@ class BER(object):
t = size & 0x7f t = size & 0x7f
if self.idx + t > len(self.content): if self.idx + t > len(self.content):
return None return None
size = util.inflate_long(self.content[self.idx : self.idx + t], True) size = util.inflate_long(self.content[self.idx: self.idx + t], True)
self.idx += t self.idx += t
if self.idx + size > len(self.content): if self.idx + size > len(self.content):
# can't fit # can't fit
return None return None
data = self.content[self.idx : self.idx + size] data = self.content[self.idx: self.idx + size]
self.idx += size self.idx += size
# now switch on id # now switch on id
if ident == 0x30: if ident == 0x30:
@ -91,9 +91,9 @@ class BER(object):
def decode_sequence(data): def decode_sequence(data):
out = [] out = []
b = BER(data) ber = BER(data)
while True: while True:
x = b.decode_next() x = ber.decode_next()
if x is None: if x is None:
break break
out.append(x) out.append(x)
@ -126,8 +126,8 @@ class BER(object):
raise BERException('Unknown type for encoding: %s' % repr(type(x))) raise BERException('Unknown type for encoding: %s' % repr(type(x)))
def encode_sequence(data): def encode_sequence(data):
b = BER() ber = BER()
for item in data: for item in data:
b.encode(item) ber.encode(item)
return b.asbytes() return ber.asbytes()
encode_sequence = staticmethod(encode_sequence) encode_sequence = staticmethod(encode_sequence)

View File

@ -25,7 +25,7 @@ read operations are blocking and can have a timeout set.
import array import array
import threading import threading
import time import time
from paramiko.common import * from paramiko.py3compat import PY2, b
class PipeTimeout (IOError): class PipeTimeout (IOError):
@ -62,7 +62,6 @@ class BufferedPipe (object):
def _buffer_tobytes(self, limit=None): def _buffer_tobytes(self, limit=None):
return self._buffer[:limit].tobytes() return self._buffer[:limit].tobytes()
def set_event(self, event): def set_event(self, event):
""" """
Set an event on this buffer. When data is ready to be read (or the Set an event on this buffer. When data is ready to be read (or the
@ -208,4 +207,3 @@ class BufferedPipe (object):
return len(self._buffer) return len(self._buffer)
finally: finally:
self._lock.release() self._lock.release()

View File

@ -21,15 +21,17 @@ Abstraction for an SSH2 channel.
""" """
import binascii import binascii
import sys
import time import time
import threading import threading
import socket import socket
import os
from paramiko.common import *
from paramiko import util from paramiko import util
from paramiko.common import cMSG_CHANNEL_REQUEST, cMSG_CHANNEL_WINDOW_ADJUST, \
cMSG_CHANNEL_DATA, cMSG_CHANNEL_EXTENDED_DATA, DEBUG, ERROR, \
cMSG_CHANNEL_SUCCESS, cMSG_CHANNEL_FAILURE, cMSG_CHANNEL_EOF, \
cMSG_CHANNEL_CLOSE
from paramiko.message import Message from paramiko.message import Message
from paramiko.py3compat import bytes_types
from paramiko.ssh_exception import SSHException from paramiko.ssh_exception import SSHException
from paramiko.file import BufferedFile from paramiko.file import BufferedFile
from paramiko.buffered_pipe import BufferedPipe, PipeTimeout from paramiko.buffered_pipe import BufferedPipe, PipeTimeout
@ -112,7 +114,7 @@ class Channel (object):
out += ' (EOF received)' out += ' (EOF received)'
if self.eof_sent: if self.eof_sent:
out += ' (EOF sent)' out += ' (EOF sent)'
out += ' (open) window=%d' % (self.out_window_size) out += ' (open) window=%d' % self.out_window_size
if len(self.in_buffer) > 0: if len(self.in_buffer) > 0:
out += ' in-buffer=%d' % (len(self.in_buffer),) out += ' in-buffer=%d' % (len(self.in_buffer),)
out += ' -> ' + repr(self.transport) out += ' -> ' + repr(self.transport)
@ -176,7 +178,7 @@ class Channel (object):
m.add_byte(cMSG_CHANNEL_REQUEST) m.add_byte(cMSG_CHANNEL_REQUEST)
m.add_int(self.remote_chanid) m.add_int(self.remote_chanid)
m.add_string('shell') m.add_string('shell')
m.add_boolean(1) m.add_boolean(True)
self._event_pending() self._event_pending()
self.transport._send_user_message(m) self.transport._send_user_message(m)
self._wait_for_event() self._wait_for_event()
@ -465,10 +467,8 @@ class Channel (object):
self._feed(data) self._feed(data)
return old return old
### socket API ### socket API
def settimeout(self, timeout): def settimeout(self, timeout):
""" """
Set a timeout on blocking read/write operations. The ``timeout`` Set a timeout on blocking read/write operations. The ``timeout``
@ -885,10 +885,8 @@ class Channel (object):
""" """
self.shutdown(1) self.shutdown(1)
### calls from Transport ### calls from Transport
def _set_transport(self, transport): def _set_transport(self, transport):
self.transport = transport self.transport = transport
self.logger = util.get_logger(self.transport.get_log_channel()) self.logger = util.get_logger(self.transport.get_log_channel())
@ -1063,10 +1061,8 @@ class Channel (object):
if m is not None: if m is not None:
self.transport._send_user_message(m) self.transport._send_user_message(m)
### internals... ### internals...
def _log(self, level, msg, *args): def _log(self, level, msg, *args):
self.logger.log(level, "[chan " + self._name + "] " + msg, *args) self.logger.log(level, "[chan " + self._name + "] " + msg, *args)
@ -1171,7 +1167,7 @@ class Channel (object):
return 0 return 0
then = time.time() then = time.time()
self.out_buffer_cv.wait(timeout) self.out_buffer_cv.wait(timeout)
if timeout != None: if timeout is not None:
timeout -= time.time() - then timeout -= time.time() - then
if timeout <= 0.0: if timeout <= 0.0:
raise socket.timeout() raise socket.timeout()
@ -1201,7 +1197,7 @@ class ChannelFile (BufferedFile):
flush the buffer. flush the buffer.
""" """
def __init__(self, channel, mode = 'r', bufsize = -1): def __init__(self, channel, mode='r', bufsize=-1):
self.channel = channel self.channel = channel
BufferedFile.__init__(self) BufferedFile.__init__(self)
self._set_mode(mode, bufsize) self._set_mode(mode, bufsize)
@ -1221,7 +1217,7 @@ class ChannelFile (BufferedFile):
class ChannelStderrFile (ChannelFile): class ChannelStderrFile (ChannelFile):
def __init__(self, channel, mode = 'r', bufsize = -1): def __init__(self, channel, mode='r', bufsize=-1):
ChannelFile.__init__(self, channel, mode, bufsize) ChannelFile.__init__(self, channel, mode, bufsize)
def _read(self, size): def _read(self, size):

View File

@ -27,10 +27,11 @@ import socket
import warnings import warnings
from paramiko.agent import Agent from paramiko.agent import Agent
from paramiko.common import * from paramiko.common import DEBUG
from paramiko.config import SSH_PORT from paramiko.config import SSH_PORT
from paramiko.dsskey import DSSKey from paramiko.dsskey import DSSKey
from paramiko.hostkeys import HostKeys from paramiko.hostkeys import HostKeys
from paramiko.py3compat import string_types
from paramiko.resource import ResourceManager from paramiko.resource import ResourceManager
from paramiko.rsakey import RSAKey from paramiko.rsakey import RSAKey
from paramiko.ssh_exception import SSHException, BadHostKeyException from paramiko.ssh_exception import SSHException, BadHostKeyException
@ -266,7 +267,7 @@ class SSHClient (object):
if key_filename is None: if key_filename is None:
key_filenames = [] key_filenames = []
elif isinstance(key_filename, string_types): elif isinstance(key_filename, string_types):
key_filenames = [ key_filename ] key_filenames = [key_filename]
else: else:
key_filenames = key_filename key_filenames = key_filename
self._auth(username, password, pkey, key_filenames, allow_agent, look_for_keys) self._auth(username, password, pkey, key_filenames, allow_agent, look_for_keys)
@ -280,7 +281,7 @@ class SSHClient (object):
self._transport.close() self._transport.close()
self._transport = None self._transport = None
if self._agent != None: if self._agent is not None:
self._agent.close() self._agent.close()
self._agent = None self._agent = None
@ -304,7 +305,7 @@ class SSHClient (object):
:raises SSHException: if the server fails to execute the command :raises SSHException: if the server fails to execute the command
""" """
chan = self._transport.open_session() chan = self._transport.open_session()
if(get_pty): if get_pty:
chan.get_pty() chan.get_pty()
chan.settimeout(timeout) chan.settimeout(timeout)
chan.exec_command(command) chan.exec_command(command)
@ -314,7 +315,7 @@ class SSHClient (object):
return stdin, stdout, stderr return stdin, stdout, stderr
def invoke_shell(self, term='vt100', width=80, height=24, width_pixels=0, def invoke_shell(self, term='vt100', width=80, height=24, width_pixels=0,
height_pixels=0): height_pixels=0):
""" """
Start an interactive shell session on the SSH server. A new `.Channel` Start an interactive shell session on the SSH server. A new `.Channel`
is opened and connected to a pseudo-terminal using the requested is opened and connected to a pseudo-terminal using the requested
@ -394,7 +395,7 @@ class SSHClient (object):
saved_exception = e saved_exception = e
if not two_factor and allow_agent: if not two_factor and allow_agent:
if self._agent == None: if self._agent is None:
self._agent = Agent() self._agent = Agent()
for key in self._agent.get_keys(): for key in self._agent.get_keys():
@ -445,8 +446,8 @@ class SSHClient (object):
try: try:
self._transport.auth_password(username, password) self._transport.auth_password(username, password)
return return
except SSHException: except SSHException as e:
saved_exception = sys.exc_info()[1] saved_exception = e
elif two_factor: elif two_factor:
raise SSHException('Two-factor authentication requires a password') raise SSHException('Two-factor authentication requires a password')

View File

@ -19,7 +19,8 @@
""" """
Common constants and global variables. Common constants and global variables.
""" """
from paramiko.py3compat import * import logging
from paramiko.py3compat import byte_chr, PY2, bytes_types, string_types, b, long
MSG_DISCONNECT, MSG_IGNORE, MSG_UNIMPLEMENTED, MSG_DEBUG, MSG_SERVICE_REQUEST, \ MSG_DISCONNECT, MSG_IGNORE, MSG_UNIMPLEMENTED, MSG_DEBUG, MSG_SERVICE_REQUEST, \
MSG_SERVICE_ACCEPT = range(1, 7) MSG_SERVICE_ACCEPT = range(1, 7)
@ -34,10 +35,35 @@ MSG_CHANNEL_OPEN, MSG_CHANNEL_OPEN_SUCCESS, MSG_CHANNEL_OPEN_FAILURE, \
MSG_CHANNEL_EOF, MSG_CHANNEL_CLOSE, MSG_CHANNEL_REQUEST, \ MSG_CHANNEL_EOF, MSG_CHANNEL_CLOSE, MSG_CHANNEL_REQUEST, \
MSG_CHANNEL_SUCCESS, MSG_CHANNEL_FAILURE = range(90, 101) MSG_CHANNEL_SUCCESS, MSG_CHANNEL_FAILURE = range(90, 101)
for key in list(locals().keys()): cMSG_DISCONNECT = byte_chr(MSG_DISCONNECT)
if key.startswith('MSG_'): cMSG_IGNORE = byte_chr(MSG_IGNORE)
locals()['c' + key] = byte_chr(locals()[key]) cMSG_UNIMPLEMENTED = byte_chr(MSG_UNIMPLEMENTED)
del key cMSG_DEBUG = byte_chr(MSG_DEBUG)
cMSG_SERVICE_REQUEST = byte_chr(MSG_SERVICE_REQUEST)
cMSG_SERVICE_ACCEPT = byte_chr(MSG_SERVICE_ACCEPT)
cMSG_KEXINIT = byte_chr(MSG_KEXINIT)
cMSG_NEWKEYS = byte_chr(MSG_NEWKEYS)
cMSG_USERAUTH_REQUEST = byte_chr(MSG_USERAUTH_REQUEST)
cMSG_USERAUTH_FAILURE = byte_chr(MSG_USERAUTH_FAILURE)
cMSG_USERAUTH_SUCCESS = byte_chr(MSG_USERAUTH_SUCCESS)
cMSG_USERAUTH_BANNER = byte_chr(MSG_USERAUTH_BANNER)
cMSG_USERAUTH_PK_OK = byte_chr(MSG_USERAUTH_PK_OK)
cMSG_USERAUTH_INFO_REQUEST = byte_chr(MSG_USERAUTH_INFO_REQUEST)
cMSG_USERAUTH_INFO_RESPONSE = byte_chr(MSG_USERAUTH_INFO_RESPONSE)
cMSG_GLOBAL_REQUEST = byte_chr(MSG_GLOBAL_REQUEST)
cMSG_REQUEST_SUCCESS = byte_chr(MSG_REQUEST_SUCCESS)
cMSG_REQUEST_FAILURE = byte_chr(MSG_REQUEST_FAILURE)
cMSG_CHANNEL_OPEN = byte_chr(MSG_CHANNEL_OPEN)
cMSG_CHANNEL_OPEN_SUCCESS = byte_chr(MSG_CHANNEL_OPEN_SUCCESS)
cMSG_CHANNEL_OPEN_FAILURE = byte_chr(MSG_CHANNEL_OPEN_FAILURE)
cMSG_CHANNEL_WINDOW_ADJUST = byte_chr(MSG_CHANNEL_WINDOW_ADJUST)
cMSG_CHANNEL_DATA = byte_chr(MSG_CHANNEL_DATA)
cMSG_CHANNEL_EXTENDED_DATA = byte_chr(MSG_CHANNEL_EXTENDED_DATA)
cMSG_CHANNEL_EOF = byte_chr(MSG_CHANNEL_EOF)
cMSG_CHANNEL_CLOSE = byte_chr(MSG_CHANNEL_CLOSE)
cMSG_CHANNEL_REQUEST = byte_chr(MSG_CHANNEL_REQUEST)
cMSG_CHANNEL_SUCCESS = byte_chr(MSG_CHANNEL_SUCCESS)
cMSG_CHANNEL_FAILURE = byte_chr(MSG_CHANNEL_FAILURE)
# for debugging: # for debugging:
MSG_NAMES = { MSG_NAMES = {
@ -105,24 +131,6 @@ from Crypto import Random
# keep a crypto-strong PRNG nearby # keep a crypto-strong PRNG nearby
rng = Random.new() rng = Random.new()
import sys
if sys.version_info < (2, 3):
try:
import logging
except:
import logging22 as logging
import select
PY22 = True
import socket
if not hasattr(socket, 'timeout'):
class timeout(socket.error): pass
socket.timeout = timeout
del timeout
else:
import logging
PY22 = False
zero_byte = byte_chr(0) zero_byte = byte_chr(0)
one_byte = byte_chr(1) one_byte = byte_chr(1)
four_byte = byte_chr(4) four_byte = byte_chr(4)

View File

@ -23,8 +23,9 @@ DSS keys.
from Crypto.PublicKey import DSA from Crypto.PublicKey import DSA
from Crypto.Hash import SHA from Crypto.Hash import SHA
from paramiko.common import *
from paramiko import util from paramiko import util
from paramiko.common import zero_byte, rng
from paramiko.py3compat import long
from paramiko.ssh_exception import SSHException from paramiko.ssh_exception import SSHException
from paramiko.message import Message from paramiko.message import Message
from paramiko.ber import BER, BERException from paramiko.ber import BER, BERException
@ -110,9 +111,9 @@ class DSSKey (PKey):
rstr = util.deflate_long(r, 0) rstr = util.deflate_long(r, 0)
sstr = util.deflate_long(s, 0) sstr = util.deflate_long(s, 0)
if len(rstr) < 20: if len(rstr) < 20:
rstr = zero_byte * (20 - len(rstr)) + rstr rstr += zero_byte * (20 - len(rstr))
if len(sstr) < 20: if len(sstr) < 20:
sstr = zero_byte * (20 - len(sstr)) + sstr sstr += zero_byte * (20 - len(sstr))
m.add_string(rstr + sstr) m.add_string(rstr + sstr)
return m return m
@ -137,7 +138,7 @@ class DSSKey (PKey):
def _encode_key(self): def _encode_key(self):
if self.x is None: if self.x is None:
raise SSHException('Not enough key information') raise SSHException('Not enough key information')
keylist = [ 0, self.p, self.q, self.g, self.y, self.x ] keylist = [0, self.p, self.q, self.g, self.y, self.x]
try: try:
b = BER() b = BER()
b.encode(keylist) b.encode(keylist)
@ -168,10 +169,8 @@ class DSSKey (PKey):
return key return key
generate = staticmethod(generate) generate = staticmethod(generate)
### internals... ### internals...
def _from_private_key_file(self, filename, password): def _from_private_key_file(self, filename, password):
data = self._read_private_key_file('DSA', filename, password) data = self._read_private_key_file('DSA', filename, password)
self._decode_key(data) self._decode_key(data)

View File

@ -22,15 +22,13 @@ L{ECDSAKey}
import binascii import binascii
from ecdsa import SigningKey, VerifyingKey, der, curves from ecdsa import SigningKey, VerifyingKey, der, curves
from ecdsa.util import number_to_string, sigencode_string, sigencode_strings, sigdecode_strings from Crypto.Hash import SHA256
from Crypto.Hash import SHA256, MD5 from ecdsa.test_pyecdsa import ECDSA
from Crypto.Cipher import DES3 from paramiko.common import four_byte, one_byte
from paramiko.common import *
from paramiko import util
from paramiko.message import Message from paramiko.message import Message
from paramiko.ber import BER, BERException
from paramiko.pkey import PKey from paramiko.pkey import PKey
from paramiko.py3compat import byte_chr, u
from paramiko.ssh_exception import SSHException from paramiko.ssh_exception import SSHException
@ -145,10 +143,8 @@ class ECDSAKey (PKey):
return key return key
generate = staticmethod(generate) generate = staticmethod(generate)
### internals... ### internals...
def _from_private_key_file(self, filename, password): def _from_private_key_file(self, filename, password):
data = self._read_private_key_file('EC', filename, password) data = self._read_private_key_file('EC', filename, password)
self._decode_key(data) self._decode_key(data)
@ -159,6 +155,7 @@ class ECDSAKey (PKey):
ALLOWED_PADDINGS = [one_byte, byte_chr(2) * 2, byte_chr(3) * 3, byte_chr(4) * 4, ALLOWED_PADDINGS = [one_byte, byte_chr(2) * 2, byte_chr(3) * 3, byte_chr(4) * 4,
byte_chr(5) * 5, byte_chr(6) * 6, byte_chr(7) * 7] byte_chr(5) * 5, byte_chr(6) * 6, byte_chr(7) * 7]
def _decode_key(self, data): def _decode_key(self, data):
s, padding = der.remove_sequence(data) s, padding = der.remove_sequence(data)
if padding: if padding:
@ -180,4 +177,4 @@ class ECDSAKey (PKey):
msg = Message(sig) msg = Message(sig)
r = msg.get_mpint() r = msg.get_mpint()
s = msg.get_mpint() s = msg.get_mpint()
return (r, s) return r, s

View File

@ -15,8 +15,9 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Paramiko; if not, write to the Free Software Foundation, Inc., # along with Paramiko; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
from paramiko.common import linefeed_byte_value, crlf, cr_byte, linefeed_byte, \
from paramiko.common import * cr_byte_value
from paramiko.py3compat import BytesIO, PY2, u, b, bytes_types
class BufferedFile (object): class BufferedFile (object):
@ -232,7 +233,7 @@ class BufferedFile (object):
pos = line.find(linefeed_byte) pos = line.find(linefeed_byte)
if self._flags & self.FLAG_UNIVERSAL_NEWLINE: if self._flags & self.FLAG_UNIVERSAL_NEWLINE:
rpos = line.find(cr_byte) rpos = line.find(cr_byte)
if (rpos >= 0) and ((rpos < pos) or (pos < 0)): if (rpos >= 0) and (rpos < pos or pos < 0):
pos = rpos pos = rpos
xpos = pos + 1 xpos = pos + 1
if (line[pos] == cr_byte_value) and (xpos < len(line)) and (line[xpos] == linefeed_byte_value): if (line[pos] == cr_byte_value) and (xpos < len(line)) and (line[xpos] == linefeed_byte_value):
@ -358,10 +359,8 @@ class BufferedFile (object):
def closed(self): def closed(self):
return self._closed return self._closed
### overrides... ### overrides...
def _read(self, size): def _read(self, size):
""" """
(subclass override) (subclass override)
@ -388,10 +387,8 @@ class BufferedFile (object):
""" """
return 0 return 0
### internals... ### internals...
def _set_mode(self, mode='r', bufsize=-1): def _set_mode(self, mode='r', bufsize=-1):
""" """
Subclasses call this method to initialize the BufferedFile. Subclasses call this method to initialize the BufferedFile.
@ -419,13 +416,13 @@ class BufferedFile (object):
self._flags |= self.FLAG_READ self._flags |= self.FLAG_READ
if ('w' in mode) or ('+' in mode): if ('w' in mode) or ('+' in mode):
self._flags |= self.FLAG_WRITE self._flags |= self.FLAG_WRITE
if ('a' in mode): if 'a' in mode:
self._flags |= self.FLAG_WRITE | self.FLAG_APPEND self._flags |= self.FLAG_WRITE | self.FLAG_APPEND
self._size = self._get_size() self._size = self._get_size()
self._pos = self._realpos = self._size self._pos = self._realpos = self._size
if ('b' in mode): if 'b' in mode:
self._flags |= self.FLAG_BINARY self._flags |= self.FLAG_BINARY
if ('U' in mode): if 'U' in mode:
self._flags |= self.FLAG_UNIVERSAL_NEWLINE self._flags |= self.FLAG_UNIVERSAL_NEWLINE
# built-in file objects have this attribute to store which kinds of # built-in file objects have this attribute to store which kinds of
# line terminations they've seen: # line terminations they've seen:

View File

@ -17,15 +17,17 @@
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
import base64
import binascii import binascii
from Crypto.Hash import SHA, HMAC from Crypto.Hash import SHA, HMAC
from paramiko.common import rng
from paramiko.py3compat import b, u, encodebytes, decodebytes
try: try:
from collections import MutableMapping from collections import MutableMapping
except ImportError: except ImportError:
# noinspection PyUnresolvedReferences
from UserDict import DictMixin as MutableMapping from UserDict import DictMixin as MutableMapping
from paramiko.common import *
from paramiko.dsskey import DSSKey from paramiko.dsskey import DSSKey
from paramiko.rsakey import RSAKey from paramiko.rsakey import RSAKey
from paramiko.util import get_logger, constant_time_bytes_eq from paramiko.util import get_logger, constant_time_bytes_eq
@ -213,7 +215,6 @@ class HostKeys (MutableMapping):
def __delitem__(self, key): def __delitem__(self, key):
k = self[key] k = self[key]
pass
def __getitem__(self, key): def __getitem__(self, key):
ret = self.lookup(key) ret = self.lookup(key)

View File

@ -23,11 +23,11 @@ client side, and a B{lot} more on the server side.
""" """
from Crypto.Hash import SHA from Crypto.Hash import SHA
from Crypto.Util import number
from paramiko.common import *
from paramiko import util from paramiko import util
from paramiko.common import DEBUG
from paramiko.message import Message from paramiko.message import Message
from paramiko.py3compat import byte_chr, byte_ord, byte_mask
from paramiko.ssh_exception import SSHException from paramiko.ssh_exception import SSHException
@ -88,10 +88,8 @@ class KexGex (object):
return self._parse_kexdh_gex_request_old(m) return self._parse_kexdh_gex_request_old(m)
raise SSHException('KexGex asked to handle packet type %d' % ptype) raise SSHException('KexGex asked to handle packet type %d' % ptype)
### internals... ### internals...
def _generate_x(self): def _generate_x(self):
# generate an "x" (1 < x < (p-1)/2). # generate an "x" (1 < x < (p-1)/2).
q = (self.p - 1) // 2 q = (self.p - 1) // 2

View File

@ -23,9 +23,10 @@ Standard SSH key exchange ("kex" if you wanna sound cool). Diffie-Hellman of
from Crypto.Hash import SHA from Crypto.Hash import SHA
from paramiko.common import *
from paramiko import util from paramiko import util
from paramiko.common import max_byte, zero_byte
from paramiko.message import Message from paramiko.message import Message
from paramiko.py3compat import byte_chr, long, byte_mask
from paramiko.ssh_exception import SSHException from paramiko.ssh_exception import SSHException
@ -39,6 +40,7 @@ G = 2
b7fffffffffffffff = byte_chr(0x7f) + max_byte * 7 b7fffffffffffffff = byte_chr(0x7f) + max_byte * 7
b0000000000000000 = zero_byte * 8 b0000000000000000 = zero_byte * 8
class KexGroup1(object): class KexGroup1(object):
name = 'diffie-hellman-group1-sha1' name = 'diffie-hellman-group1-sha1'
@ -71,10 +73,8 @@ class KexGroup1(object):
return self._parse_kexdh_reply(m) return self._parse_kexdh_reply(m)
raise SSHException('KexGroup1 asked to handle packet type %d' % ptype) raise SSHException('KexGroup1 asked to handle packet type %d' % ptype)
### internals... ### internals...
def _generate_x(self): def _generate_x(self):
# generate an "x" (1 < x < q), where q is (p-1)/2. # generate an "x" (1 < x < q), where q is (p-1)/2.
# p is a 128-byte (1024-bit) number, where the first 64 bits are 1. # p is a 128-byte (1024-bit) number, where the first 64 bits are 1.
@ -84,8 +84,8 @@ class KexGroup1(object):
while 1: while 1:
x_bytes = self.transport.rng.read(128) x_bytes = self.transport.rng.read(128)
x_bytes = byte_mask(x_bytes[0], 0x7f) + x_bytes[1:] x_bytes = byte_mask(x_bytes[0], 0x7f) + x_bytes[1:]
if (x_bytes[:8] != b7fffffffffffffff) and \ if (x_bytes[:8] != b7fffffffffffffff and
(x_bytes[:8] != b0000000000000000): x_bytes[:8] != b0000000000000000):
break break
self.x = util.inflate_long(x_bytes) self.x = util.inflate_long(x_bytes)

View File

@ -1,66 +0,0 @@
# Copyright (C) 2003-2007 Robey Pointer <robeypointer@gmail.com>
#
# This file is part of paramiko.
#
# Paramiko is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 2.1 of the License, or (at your option)
# any later version.
#
# 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.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Paramiko; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
"""
Stub out logging on Python < 2.3.
"""
DEBUG = 10
INFO = 20
WARNING = 30
ERROR = 40
CRITICAL = 50
def getLogger(name):
return _logger
class logger (object):
def __init__(self):
self.handlers = [ ]
self.level = ERROR
def setLevel(self, level):
self.level = level
def addHandler(self, h):
self.handlers.append(h)
def addFilter(self, filter):
pass
def log(self, level, text):
if level >= self.level:
for h in self.handlers:
h.f.write(text + '\n')
h.f.flush()
class StreamHandler (object):
def __init__(self, f):
self.f = f
def setFormatter(self, f):
pass
class Formatter (object):
def __init__(self, x, y):
pass
_logger = logger()

View File

@ -23,7 +23,8 @@ Implementation of an SSH2 "message".
import struct import struct
from paramiko import util from paramiko import util
from paramiko.common import * from paramiko.common import zero_byte, max_byte, one_byte, asbytes
from paramiko.py3compat import long, BytesIO, u, integer_types
class Message (object): class Message (object):
@ -47,7 +48,7 @@ class Message (object):
the byte stream to use as the message content (passed in only when the byte stream to use as the message content (passed in only when
decomposing a message). decomposing a message).
""" """
if content != None: if content is not None:
self.packet = BytesIO(content) self.packet = BytesIO(content)
else: else:
self.packet = BytesIO() self.packet = BytesIO()
@ -105,8 +106,8 @@ class Message (object):
bytes remaining in the message. bytes remaining in the message.
""" """
b = self.packet.read(n) b = self.packet.read(n)
max_pad_size = 1<<20 # Limit padding to 1 MB max_pad_size = 1 << 20 # Limit padding to 1 MB
if len(b) < n and n < max_pad_size: if len(b) < n < max_pad_size:
return b + zero_byte * (n - len(b)) return b + zero_byte * (n - len(b))
return b return b

View File

@ -21,14 +21,15 @@ Packet handling
""" """
import errno import errno
import select
import socket import socket
import struct import struct
import threading import threading
import time import time
from paramiko.common import *
from paramiko import util from paramiko import util
from paramiko.common import linefeed_byte, cr_byte_value, asbytes, MSG_NAMES, \
DEBUG, xffffffff, zero_byte, rng
from paramiko.py3compat import u, byte_ord
from paramiko.ssh_exception import SSHException, ProxyCommandFailure from paramiko.ssh_exception import SSHException, ProxyCommandFailure
from paramiko.message import Message from paramiko.message import Message
@ -57,8 +58,8 @@ class Packetizer (object):
REKEY_PACKETS = pow(2, 29) REKEY_PACKETS = pow(2, 29)
REKEY_BYTES = pow(2, 29) REKEY_BYTES = pow(2, 29)
REKEY_PACKETS_OVERFLOW_MAX = pow(2,29) # Allow receiving this many packets after a re-key request before terminating REKEY_PACKETS_OVERFLOW_MAX = pow(2, 29) # Allow receiving this many packets after a re-key request before terminating
REKEY_BYTES_OVERFLOW_MAX = pow(2,29) # Allow receiving this many bytes after a re-key request before terminating REKEY_BYTES_OVERFLOW_MAX = pow(2, 29) # Allow receiving this many bytes after a re-key request before terminating
def __init__(self, socket): def __init__(self, socket):
self.__socket = socket self.__socket = socket
@ -201,8 +202,6 @@ class Packetizer (object):
out = self.__remainder[:n] out = self.__remainder[:n]
self.__remainder = self.__remainder[n:] self.__remainder = self.__remainder[n:]
n -= len(out) n -= len(out)
if PY22:
return self._py22_read_all(n, out)
while n > 0: while n > 0:
got_timeout = False got_timeout = False
try: try:
@ -251,7 +250,7 @@ class Packetizer (object):
else: else:
n = -1 n = -1
except ProxyCommandFailure: except ProxyCommandFailure:
raise # so it doesn't get swallowed by the below catchall raise # so it doesn't get swallowed by the below catchall
except Exception: except Exception:
# could be: (32, 'Broken pipe') # could be: (32, 'Broken pipe')
n = -1 n = -1
@ -275,7 +274,7 @@ class Packetizer (object):
while not linefeed_byte in buf: while not linefeed_byte in buf:
buf += self._read_timeout(timeout) buf += self._read_timeout(timeout)
n = buf.index(linefeed_byte) n = buf.index(linefeed_byte)
self.__remainder = buf[n+1:] self.__remainder = buf[n + 1:]
buf = buf[:n] buf = buf[:n]
if (len(buf) > 0) and (buf[-1] == cr_byte_value): if (len(buf) > 0) and (buf[-1] == cr_byte_value):
buf = buf[:-1] buf = buf[:-1]
@ -301,12 +300,12 @@ class Packetizer (object):
if self.__dump_packets: if self.__dump_packets:
self._log(DEBUG, 'Write packet <%s>, length %d' % (cmd_name, orig_len)) self._log(DEBUG, 'Write packet <%s>, length %d' % (cmd_name, orig_len))
self._log(DEBUG, util.format_binary(packet, 'OUT: ')) self._log(DEBUG, util.format_binary(packet, 'OUT: '))
if self.__block_engine_out != None: if self.__block_engine_out is not None:
out = self.__block_engine_out.encrypt(packet) out = self.__block_engine_out.encrypt(packet)
else: else:
out = packet out = packet
# + mac # + mac
if self.__block_engine_out != None: if self.__block_engine_out is not None:
payload = struct.pack('>I', self.__sequence_number_out) + packet payload = struct.pack('>I', self.__sequence_number_out) + packet
out += compute_hmac(self.__mac_key_out, payload, self.__mac_engine_out)[:self.__mac_size_out] out += compute_hmac(self.__mac_key_out, payload, self.__mac_engine_out)[:self.__mac_size_out]
self.__sequence_number_out = (self.__sequence_number_out + 1) & xffffffff self.__sequence_number_out = (self.__sequence_number_out + 1) & xffffffff
@ -314,8 +313,8 @@ class Packetizer (object):
self.__sent_bytes += len(out) self.__sent_bytes += len(out)
self.__sent_packets += 1 self.__sent_packets += 1
if ((self.__sent_packets >= self.REKEY_PACKETS) or (self.__sent_bytes >= self.REKEY_BYTES)) \ if (self.__sent_packets >= self.REKEY_PACKETS or self.__sent_bytes >= self.REKEY_BYTES)\
and not self.__need_rekey: and not self.__need_rekey:
# only ask once for rekeying # only ask once for rekeying
self._log(DEBUG, 'Rekeying (hit %d packets, %d bytes sent)' % self._log(DEBUG, 'Rekeying (hit %d packets, %d bytes sent)' %
(self.__sent_packets, self.__sent_bytes)) (self.__sent_packets, self.__sent_bytes))
@ -334,10 +333,10 @@ class Packetizer (object):
:raises NeedRekeyException: if the transport should rekey :raises NeedRekeyException: if the transport should rekey
""" """
header = self.read_all(self.__block_size_in, check_rekey=True) header = self.read_all(self.__block_size_in, check_rekey=True)
if self.__block_engine_in != None: if self.__block_engine_in is not None:
header = self.__block_engine_in.decrypt(header) header = self.__block_engine_in.decrypt(header)
if self.__dump_packets: if self.__dump_packets:
self._log(DEBUG, util.format_binary(header, 'IN: ')); self._log(DEBUG, util.format_binary(header, 'IN: '))
packet_size = struct.unpack('>I', header[:4])[0] packet_size = struct.unpack('>I', header[:4])[0]
# leftover contains decrypted bytes from the first block (after the length field) # leftover contains decrypted bytes from the first block (after the length field)
leftover = header[4:] leftover = header[4:]
@ -346,10 +345,10 @@ class Packetizer (object):
buf = self.read_all(packet_size + self.__mac_size_in - len(leftover)) buf = self.read_all(packet_size + self.__mac_size_in - len(leftover))
packet = buf[:packet_size - len(leftover)] packet = buf[:packet_size - len(leftover)]
post_packet = buf[packet_size - len(leftover):] post_packet = buf[packet_size - len(leftover):]
if self.__block_engine_in != None: if self.__block_engine_in is not None:
packet = self.__block_engine_in.decrypt(packet) packet = self.__block_engine_in.decrypt(packet)
if self.__dump_packets: if self.__dump_packets:
self._log(DEBUG, util.format_binary(packet, 'IN: ')); self._log(DEBUG, util.format_binary(packet, 'IN: '))
packet = leftover + packet packet = leftover + packet
if self.__mac_size_in > 0: if self.__mac_size_in > 0:
@ -401,10 +400,8 @@ class Packetizer (object):
self._log(DEBUG, 'Read packet <%s>, length %d' % (cmd_name, len(payload))) self._log(DEBUG, 'Read packet <%s>, length %d' % (cmd_name, len(payload)))
return cmd, msg return cmd, msg
########## protected ########## protected
def _log(self, level, msg): def _log(self, level, msg):
if self.__logger is None: if self.__logger is None:
return return
@ -416,7 +413,7 @@ class Packetizer (object):
def _check_keepalive(self): def _check_keepalive(self):
if (not self.__keepalive_interval) or (not self.__block_engine_out) or \ if (not self.__keepalive_interval) or (not self.__block_engine_out) or \
self.__need_rekey: self.__need_rekey:
# wait till we're encrypting, and not in the middle of rekeying # wait till we're encrypting, and not in the middle of rekeying
return return
now = time.time() now = time.time()
@ -424,40 +421,7 @@ class Packetizer (object):
self.__keepalive_callback() self.__keepalive_callback()
self.__keepalive_last = now self.__keepalive_last = now
def _py22_read_all(self, n, out):
while n > 0:
r, w, e = select.select([self.__socket], [], [], 0.1)
if self.__socket not in r:
if self.__closed:
raise EOFError()
self._check_keepalive()
else:
x = self.__socket.recv(n)
if len(x) == 0:
raise EOFError()
out += x
n -= len(x)
return out
def _py22_read_timeout(self, timeout):
start = time.time()
while True:
r, w, e = select.select([self.__socket], [], [], 0.1)
if self.__socket in r:
x = self.__socket.recv(1)
if len(x) == 0:
raise EOFError()
break
if self.__closed:
raise EOFError()
now = time.time()
if now - start >= timeout:
raise socket.timeout()
return x
def _read_timeout(self, timeout): def _read_timeout(self, timeout):
if PY22:
return self._py22_read_timeout(timeout)
start = time.time() start = time.time()
while True: while True:
try: try:
@ -468,8 +432,8 @@ class Packetizer (object):
except socket.timeout: except socket.timeout:
pass pass
except EnvironmentError as e: except EnvironmentError as e:
if ((type(e.args) is tuple) and (len(e.args) > 0) and if (type(e.args) is tuple and len(e.args) > 0 and
(e.args[0] == errno.EINTR)): e.args[0] == errno.EINTR):
pass pass
else: else:
raise raise

View File

@ -28,10 +28,9 @@ will trigger as readable in `select <select.select>`.
import sys import sys
import os import os
import socket import socket
from paramiko.py3compat import b
def make_pipe (): def make_pipe():
if sys.platform[:3] != 'win': if sys.platform[:3] != 'win':
p = PosixPipe() p = PosixPipe()
else: else:
@ -40,34 +39,34 @@ def make_pipe ():
class PosixPipe (object): class PosixPipe (object):
def __init__ (self): def __init__(self):
self._rfd, self._wfd = os.pipe() self._rfd, self._wfd = os.pipe()
self._set = False self._set = False
self._forever = False self._forever = False
self._closed = False self._closed = False
def close (self): def close(self):
os.close(self._rfd) os.close(self._rfd)
os.close(self._wfd) os.close(self._wfd)
# used for unit tests: # used for unit tests:
self._closed = True self._closed = True
def fileno (self): def fileno(self):
return self._rfd return self._rfd
def clear (self): def clear(self):
if not self._set or self._forever: if not self._set or self._forever:
return return
os.read(self._rfd, 1) os.read(self._rfd, 1)
self._set = False self._set = False
def set (self): def set(self):
if self._set or self._closed: if self._set or self._closed:
return return
self._set = True self._set = True
os.write(self._wfd, b'*') os.write(self._wfd, b'*')
def set_forever (self): def set_forever(self):
self._forever = True self._forever = True
self.set() self.set()
@ -77,7 +76,7 @@ class WindowsPipe (object):
On Windows, only an OS-level "WinSock" may be used in select(), but reads On Windows, only an OS-level "WinSock" may be used in select(), but reads
and writes must be to the actual socket object. and writes must be to the actual socket object.
""" """
def __init__ (self): def __init__(self):
serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serv.bind(('127.0.0.1', 0)) serv.bind(('127.0.0.1', 0))
serv.listen(1) serv.listen(1)
@ -92,13 +91,13 @@ class WindowsPipe (object):
self._forever = False self._forever = False
self._closed = False self._closed = False
def close (self): def close(self):
self._rsock.close() self._rsock.close()
self._wsock.close() self._wsock.close()
# used for unit tests: # used for unit tests:
self._closed = True self._closed = True
def fileno (self): def fileno(self):
return self._rsock.fileno() return self._rsock.fileno()
def clear (self): def clear (self):

View File

@ -27,9 +27,9 @@ import os
from Crypto.Hash import MD5 from Crypto.Hash import MD5
from Crypto.Cipher import DES3, AES from Crypto.Cipher import DES3, AES
from paramiko.common import *
from paramiko import util from paramiko import util
from paramiko.message import Message from paramiko.common import o600, rng, zero_byte
from paramiko.py3compat import u, encodebytes, decodebytes, b
from paramiko.ssh_exception import SSHException, PasswordRequiredException from paramiko.ssh_exception import SSHException, PasswordRequiredException
@ -40,11 +40,10 @@ class PKey (object):
# known encryption types for private key files: # known encryption types for private key files:
_CIPHER_TABLE = { _CIPHER_TABLE = {
'AES-128-CBC': { 'cipher': AES, 'keysize': 16, 'blocksize': 16, 'mode': AES.MODE_CBC }, 'AES-128-CBC': {'cipher': AES, 'keysize': 16, 'blocksize': 16, 'mode': AES.MODE_CBC},
'DES-EDE3-CBC': { 'cipher': DES3, 'keysize': 24, 'blocksize': 8, 'mode': DES3.MODE_CBC }, 'DES-EDE3-CBC': {'cipher': DES3, 'keysize': 24, 'blocksize': 8, 'mode': DES3.MODE_CBC},
} }
def __init__(self, msg=None, data=None): def __init__(self, msg=None, data=None):
""" """
Create a new instance of this public key type. If ``msg`` is given, Create a new instance of this public key type. If ``msg`` is given,
@ -73,6 +72,7 @@ class PKey (object):
def __str__(self): def __str__(self):
return self.asbytes() return self.asbytes()
# noinspection PyUnresolvedReferences
def __cmp__(self, other): def __cmp__(self, other):
""" """
Compare this key to another. Returns 0 if this key is equivalent to Compare this key to another. Returns 0 if this key is equivalent to
@ -345,7 +345,7 @@ class PKey (object):
s = u(encodebytes(data)) s = u(encodebytes(data))
# re-wrap to 64-char lines # re-wrap to 64-char lines
s = ''.join(s.split('\n')) s = ''.join(s.split('\n'))
s = '\n'.join([s[i : i+64] for i in range(0, len(s), 64)]) s = '\n'.join([s[i: i + 64] for i in range(0, len(s), 64)])
f.write(s) f.write(s)
f.write('\n') f.write('\n')
f.write('-----END %s PRIVATE KEY-----\n' % tag) f.write('-----END %s PRIVATE KEY-----\n' % tag)

View File

@ -23,16 +23,16 @@ Utility functions for dealing with primes.
from Crypto.Util import number from Crypto.Util import number
from paramiko import util from paramiko import util
from paramiko.py3compat import byte_mask, long
from paramiko.ssh_exception import SSHException from paramiko.ssh_exception import SSHException
from paramiko.common import *
def _generate_prime(bits, rng): def _generate_prime(bits, rng):
"primtive attempt at prime generation" """primtive attempt at prime generation"""
hbyte_mask = pow(2, bits % 8) - 1 hbyte_mask = pow(2, bits % 8) - 1
while True: while True:
# loop catches the case where we increment n into a higher bit-range # loop catches the case where we increment n into a higher bit-range
x = rng.read((bits+7) // 8) x = rng.read((bits + 7) // 8)
if hbyte_mask > 0: if hbyte_mask > 0:
x = byte_mask(x[0], hbyte_mask) + x[1:] x = byte_mask(x[0], hbyte_mask) + x[1:]
n = util.inflate_long(x, 1) n = util.inflate_long(x, 1)
@ -44,9 +44,10 @@ def _generate_prime(bits, rng):
break break
return n return n
def _roll_random(rng, n): def _roll_random(rng, n):
"returns a random # from 0 to N-1" """returns a random # from 0 to N-1"""
bits = util.bit_length(n-1) bits = util.bit_length(n - 1)
byte_count = (bits + 7) // 8 byte_count = (bits + 7) // 8
hbyte_mask = pow(2, bits % 8) - 1 hbyte_mask = pow(2, bits % 8) - 1
@ -130,7 +131,7 @@ class ModulusPack (object):
good = -1 good = -1
# find nearest bitsize >= preferred # find nearest bitsize >= preferred
for b in bitsizes: for b in bitsizes:
if (b >= prefer) and (b < max) and ((b < good) or (good == -1)): if (b >= prefer) and (b < max) and (b < good or good == -1):
good = b good = b
# if that failed, find greatest bitsize >= min # if that failed, find greatest bitsize >= min
if good == -1: if good == -1:

View File

@ -80,7 +80,7 @@ class ProxyCommand(object):
while len(self.buffer) < size: while len(self.buffer) < size:
if self.timeout is not None: if self.timeout is not None:
elapsed = (datetime.now() - start).microseconds elapsed = (datetime.now() - start).microseconds
timeout = self.timeout * 1000 * 1000 # to microseconds timeout = self.timeout * 1000 * 1000 # to microseconds
if elapsed >= timeout: if elapsed >= timeout:
raise socket.timeout() raise socket.timeout()
r, w, x = select([self.process.stdout], [], [], 0.0) r, w, x = select([self.process.stdout], [], [], 0.0)
@ -94,7 +94,7 @@ class ProxyCommand(object):
self.buffer = [] self.buffer = []
return result return result
except socket.timeout: except socket.timeout:
raise # socket.timeout is a subclass of IOError raise # socket.timeout is a subclass of IOError
except IOError as e: except IOError as e:
raise ProxyCommandFailure(' '.join(self.cmd), e.strerror) raise ProxyCommandFailure(' '.join(self.cmd), e.strerror)

View File

@ -21,14 +21,14 @@ RSA keys.
""" """
from Crypto.PublicKey import RSA from Crypto.PublicKey import RSA
from Crypto.Hash import SHA, MD5 from Crypto.Hash import SHA
from Crypto.Cipher import DES3
from paramiko.common import *
from paramiko import util from paramiko import util
from paramiko.common import rng, max_byte, zero_byte, one_byte
from paramiko.message import Message from paramiko.message import Message
from paramiko.ber import BER, BERException from paramiko.ber import BER, BERException
from paramiko.pkey import PKey from paramiko.pkey import PKey
from paramiko.py3compat import long
from paramiko.ssh_exception import SSHException from paramiko.ssh_exception import SSHException
SHA1_DIGESTINFO = b'\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14' SHA1_DIGESTINFO = b'\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14'
@ -113,9 +113,9 @@ class RSAKey (PKey):
def _encode_key(self): def _encode_key(self):
if (self.p is None) or (self.q is None): if (self.p is None) or (self.q is None):
raise SSHException('Not enough key info to write private key file') raise SSHException('Not enough key info to write private key file')
keylist = [ 0, self.n, self.e, self.d, self.p, self.q, keylist = [0, self.n, self.e, self.d, self.p, self.q,
self.d % (self.p - 1), self.d % (self.q - 1), self.d % (self.p - 1), self.d % (self.q - 1),
util.mod_inverse(self.q, self.p) ] util.mod_inverse(self.q, self.p)]
try: try:
b = BER() b = BER()
b.encode(keylist) b.encode(keylist)
@ -148,10 +148,8 @@ class RSAKey (PKey):
return key return key
generate = staticmethod(generate) generate = staticmethod(generate)
### internals... ### internals...
def _pkcs1imify(self, data): def _pkcs1imify(self, data):
""" """
turn a 20-byte SHA1 hash into a blob of data as large as the key's N, turn a 20-byte SHA1 hash into a blob of data as large as the key's N,

View File

@ -21,8 +21,9 @@
""" """
import threading import threading
from paramiko.common import *
from paramiko import util from paramiko import util
from paramiko.common import DEBUG, ERROR, OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED, AUTH_FAILED
from paramiko.py3compat import string_types
class ServerInterface (object): class ServerInterface (object):
@ -291,10 +292,8 @@ class ServerInterface (object):
""" """
return False return False
### Channel requests ### Channel requests
def check_channel_pty_request(self, channel, term, width, height, pixelwidth, pixelheight, def check_channel_pty_request(self, channel, term, width, height, pixelwidth, pixelheight,
modes): modes):
""" """

View File

@ -20,32 +20,31 @@ import select
import socket import socket
import struct import struct
from paramiko.common import *
from paramiko import util from paramiko import util
from paramiko.channel import Channel from paramiko.common import asbytes, DEBUG
from paramiko.message import Message from paramiko.message import Message
from paramiko.py3compat import byte_chr, byte_ord
CMD_INIT, CMD_VERSION, CMD_OPEN, CMD_CLOSE, CMD_READ, CMD_WRITE, CMD_LSTAT, CMD_FSTAT, \ CMD_INIT, CMD_VERSION, CMD_OPEN, CMD_CLOSE, CMD_READ, CMD_WRITE, CMD_LSTAT, CMD_FSTAT, \
CMD_SETSTAT, CMD_FSETSTAT, CMD_OPENDIR, CMD_READDIR, CMD_REMOVE, CMD_MKDIR, \ CMD_SETSTAT, CMD_FSETSTAT, CMD_OPENDIR, CMD_READDIR, CMD_REMOVE, CMD_MKDIR, \
CMD_RMDIR, CMD_REALPATH, CMD_STAT, CMD_RENAME, CMD_READLINK, CMD_SYMLINK \ CMD_RMDIR, CMD_REALPATH, CMD_STAT, CMD_RENAME, CMD_READLINK, CMD_SYMLINK = range(1, 21)
= range(1, 21)
CMD_STATUS, CMD_HANDLE, CMD_DATA, CMD_NAME, CMD_ATTRS = range(101, 106) CMD_STATUS, CMD_HANDLE, CMD_DATA, CMD_NAME, CMD_ATTRS = range(101, 106)
CMD_EXTENDED, CMD_EXTENDED_REPLY = range(200, 202) CMD_EXTENDED, CMD_EXTENDED_REPLY = range(200, 202)
SFTP_OK = 0 SFTP_OK = 0
SFTP_EOF, SFTP_NO_SUCH_FILE, SFTP_PERMISSION_DENIED, SFTP_FAILURE, SFTP_BAD_MESSAGE, \ SFTP_EOF, SFTP_NO_SUCH_FILE, SFTP_PERMISSION_DENIED, SFTP_FAILURE, SFTP_BAD_MESSAGE, \
SFTP_NO_CONNECTION, SFTP_CONNECTION_LOST, SFTP_OP_UNSUPPORTED = range(1, 9) SFTP_NO_CONNECTION, SFTP_CONNECTION_LOST, SFTP_OP_UNSUPPORTED = range(1, 9)
SFTP_DESC = [ 'Success', SFTP_DESC = ['Success',
'End of file', 'End of file',
'No such file', 'No such file',
'Permission denied', 'Permission denied',
'Failure', 'Failure',
'Bad message', 'Bad message',
'No connection', 'No connection',
'Connection lost', 'Connection lost',
'Operation unsupported' ] 'Operation unsupported']
SFTP_FLAG_READ = 0x1 SFTP_FLAG_READ = 0x1
SFTP_FLAG_WRITE = 0x2 SFTP_FLAG_WRITE = 0x2
@ -99,10 +98,8 @@ class BaseSFTP (object):
self.sock = None self.sock = None
self.ultra_debug = False self.ultra_debug = False
### internals... ### internals...
def _send_version(self): def _send_version(self):
self._send_packet(CMD_INIT, struct.pack('>I', _VERSION)) self._send_packet(CMD_INIT, struct.pack('>I', _VERSION))
t, data = self._read_packet() t, data = self._read_packet()
@ -121,7 +118,7 @@ class BaseSFTP (object):
raise SFTPError('Incompatible sftp protocol') raise SFTPError('Incompatible sftp protocol')
version = struct.unpack('>I', data[:4])[0] version = struct.unpack('>I', data[:4])[0]
# advertise that we support "check-file" # advertise that we support "check-file"
extension_pairs = [ 'check-file', 'md5,sha1' ] extension_pairs = ['check-file', 'md5,sha1']
msg = Message() msg = Message()
msg.add_int(_VERSION) msg.add_int(_VERSION)
msg.add(*extension_pairs) msg.add(*extension_pairs)
@ -151,7 +148,7 @@ class BaseSFTP (object):
# return or raise an exception, but calling select on a closed # return or raise an exception, but calling select on a closed
# socket will.) # socket will.)
while True: while True:
read, write, err = select.select([ self.sock ], [], [], 0.1) read, write, err = select.select([self.sock], [], [], 0.1)
if len(read) > 0: if len(read) > 0:
x = self.sock.recv(n) x = self.sock.recv(n)
break break
@ -181,7 +178,7 @@ class BaseSFTP (object):
size = struct.unpack('>I', x)[0] size = struct.unpack('>I', x)[0]
data = self._read_all(size) data = self._read_all(size)
if self.ultra_debug: if self.ultra_debug:
self._log(DEBUG, util.format_binary(data, 'IN: ')); self._log(DEBUG, util.format_binary(data, 'IN: '))
if size > 0: if size > 0:
t = byte_ord(data[0]) t = byte_ord(data[0])
#self._log(DEBUG2, 'read: %s (len=%d)' % (CMD_NAMES.get(t), '0x%02x' % t, len(data)-1)) #self._log(DEBUG2, 'read: %s (len=%d)' % (CMD_NAMES.get(t), '0x%02x' % t, len(data)-1))

View File

@ -18,8 +18,8 @@
import stat import stat
import time import time
from paramiko.common import * from paramiko.common import x80000000, o700, o70, xffffffff
from paramiko.sftp import * from paramiko.py3compat import long, b
class SFTPAttributes (object): class SFTPAttributes (object):
@ -84,10 +84,8 @@ class SFTPAttributes (object):
def __repr__(self): def __repr__(self):
return '<SFTPAttributes: %s>' % self._debug_str() return '<SFTPAttributes: %s>' % self._debug_str()
### internals... ### internals...
def _from_msg(cls, msg, filename=None, longname=None): def _from_msg(cls, msg, filename=None, longname=None):
attr = cls() attr = cls()
attr._unpack(msg) attr._unpack(msg)
@ -173,7 +171,7 @@ class SFTPAttributes (object):
_rwx = staticmethod(_rwx) _rwx = staticmethod(_rwx)
def __str__(self): def __str__(self):
"create a unix-style long description of the file (like ls -l)" """create a unix-style long description of the file (like ls -l)"""
if self.st_mode is not None: if self.st_mode is not None:
kind = stat.S_IFMT(self.st_mode) kind = stat.S_IFMT(self.st_mode)
if kind == stat.S_IFIFO: if kind == stat.S_IFIFO:

View File

@ -24,8 +24,18 @@ import stat
import threading import threading
import time import time
import weakref import weakref
from paramiko import util
from paramiko.channel import Channel
from paramiko.message import Message
from paramiko.common import INFO, DEBUG, o777
from paramiko.py3compat import bytestring, b, u, long, string_types, bytes_types
from paramiko.sftp import BaseSFTP, CMD_OPENDIR, CMD_HANDLE, SFTPError, CMD_READDIR, \
CMD_NAME, CMD_CLOSE, SFTP_FLAG_READ, SFTP_FLAG_WRITE, SFTP_FLAG_CREATE, \
SFTP_FLAG_TRUNC, SFTP_FLAG_APPEND, SFTP_FLAG_EXCL, CMD_OPEN, CMD_REMOVE, \
CMD_RENAME, CMD_MKDIR, CMD_RMDIR, CMD_STAT, CMD_ATTRS, CMD_LSTAT, \
CMD_SYMLINK, CMD_SETSTAT, CMD_READLINK, CMD_REALPATH, CMD_STATUS, SFTP_OK, \
SFTP_EOF, SFTP_NO_SUCH_FILE, SFTP_PERMISSION_DENIED
from paramiko.sftp import *
from paramiko.sftp_attr import SFTPAttributes from paramiko.sftp_attr import SFTPAttributes
from paramiko.ssh_exception import SSHException from paramiko.ssh_exception import SSHException
from paramiko.sftp_file import SFTPFile from paramiko.sftp_file import SFTPFile
@ -47,6 +57,7 @@ def _to_unicode(s):
b_slash = b'/' b_slash = b'/'
class SFTPClient(BaseSFTP): class SFTPClient(BaseSFTP):
""" """
SFTP client object. SFTP client object.
@ -106,9 +117,9 @@ class SFTPClient(BaseSFTP):
def _log(self, level, msg, *args): def _log(self, level, msg, *args):
if isinstance(msg, list): if isinstance(msg, list):
for m in msg: for m in msg:
super(SFTPClient, self)._log(level, "[chan %s] " + m, *([ self.sock.get_name() ] + list(args))) super(SFTPClient, self)._log(level, "[chan %s] " + m, *([self.sock.get_name()] + list(args)))
else: else:
super(SFTPClient, self)._log(level, "[chan %s] " + msg, *([ self.sock.get_name() ] + list(args))) super(SFTPClient, self)._log(level, "[chan %s] " + msg, *([self.sock.get_name()] + list(args)))
def close(self): def close(self):
""" """
@ -222,11 +233,11 @@ class SFTPClient(BaseSFTP):
imode |= SFTP_FLAG_READ imode |= SFTP_FLAG_READ
if ('w' in mode) or ('+' in mode) or ('a' in mode): if ('w' in mode) or ('+' in mode) or ('a' in mode):
imode |= SFTP_FLAG_WRITE imode |= SFTP_FLAG_WRITE
if ('w' in mode): if 'w' in mode:
imode |= SFTP_FLAG_CREATE | SFTP_FLAG_TRUNC imode |= SFTP_FLAG_CREATE | SFTP_FLAG_TRUNC
if ('a' in mode): if 'a' in mode:
imode |= SFTP_FLAG_CREATE | SFTP_FLAG_APPEND imode |= SFTP_FLAG_CREATE | SFTP_FLAG_APPEND
if ('x' in mode): if 'x' in mode:
imode |= SFTP_FLAG_CREATE | SFTP_FLAG_EXCL imode |= SFTP_FLAG_CREATE | SFTP_FLAG_EXCL
attrblock = SFTPAttributes() attrblock = SFTPAttributes()
t, msg = self._request(CMD_OPEN, filename, imode, attrblock) t, msg = self._request(CMD_OPEN, filename, imode, attrblock)
@ -629,10 +640,8 @@ class SFTPClient(BaseSFTP):
if s.st_size != size: if s.st_size != size:
raise IOError('size mismatch in get! %d != %d' % (s.st_size, size)) raise IOError('size mismatch in get! %d != %d' % (s.st_size, size))
### internals... ### internals...
def _request(self, t, *arg): def _request(self, t, *arg):
num = self._async_request(type(None), t, *arg) num = self._async_request(type(None), t, *arg)
return self._read_response(num) return self._read_response(num)
@ -689,7 +698,7 @@ class SFTPClient(BaseSFTP):
if waitfor is None: if waitfor is None:
# just doing a single check # just doing a single check
break break
return (None, None) return None, None
def _finish_responses(self, fileobj): def _finish_responses(self, fileobj):
while fileobj in self._expecting.values(): while fileobj in self._expecting.values():

View File

@ -27,10 +27,12 @@ from collections import deque
import socket import socket
import threading import threading
import time import time
from paramiko.common import DEBUG
from paramiko.common import *
from paramiko.sftp import *
from paramiko.file import BufferedFile from paramiko.file import BufferedFile
from paramiko.py3compat import long
from paramiko.sftp import CMD_CLOSE, CMD_READ, CMD_DATA, SFTPError, CMD_WRITE, \
CMD_STATUS, CMD_FSTAT, CMD_ATTRS, CMD_FSETSTAT, CMD_EXTENDED
from paramiko.sftp_attr import SFTPAttributes from paramiko.sftp_attr import SFTPAttributes
@ -437,11 +439,9 @@ class SFTPFile (BufferedFile):
for x in chunks: for x in chunks:
self.seek(x[0]) self.seek(x[0])
yield self.read(x[1]) yield self.read(x[1])
### internals... ### internals...
def _get_size(self): def _get_size(self):
try: try:
return self.stat().st_size return self.stat().st_size
@ -483,7 +483,7 @@ class SFTPFile (BufferedFile):
self._prefetch_done = True self._prefetch_done = True
def _check_exception(self): def _check_exception(self):
"if there's a saved exception, raise & clear it" """if there's a saved exception, raise & clear it"""
if self._saved_exception is not None: if self._saved_exception is not None:
x = self._saved_exception x = self._saved_exception
self._saved_exception = None self._saved_exception = None

View File

@ -21,9 +21,7 @@ Abstraction of an SFTP file handle (for server mode).
""" """
import os import os
from paramiko.sftp import SFTP_OP_UNSUPPORTED, SFTP_OK
from paramiko.common import *
from paramiko.sftp import *
class SFTPHandle (object): class SFTPHandle (object):
@ -46,7 +44,7 @@ class SFTPHandle (object):
self.__flags = flags self.__flags = flags
self.__name = None self.__name = None
# only for handles to folders: # only for handles to folders:
self.__files = { } self.__files = {}
self.__tell = None self.__tell = None
def close(self): def close(self):
@ -166,10 +164,8 @@ class SFTPHandle (object):
""" """
return SFTP_OP_UNSUPPORTED return SFTP_OP_UNSUPPORTED
### internals... ### internals...
def _set_files(self, files): def _set_files(self, files):
""" """
Used by the SFTP server code to cache a directory listing. (In Used by the SFTP server code to cache a directory listing. (In

View File

@ -24,14 +24,26 @@ import os
import errno import errno
from Crypto.Hash import MD5, SHA from Crypto.Hash import MD5, SHA
from paramiko.common import * import sys
from paramiko import util
from paramiko.sftp import BaseSFTP, Message, SFTP_FAILURE, \
SFTP_PERMISSION_DENIED, SFTP_NO_SUCH_FILE
from paramiko.sftp_si import SFTPServerInterface
from paramiko.sftp_attr import SFTPAttributes
from paramiko.common import DEBUG
from paramiko.py3compat import long, string_types, bytes_types, b
from paramiko.server import SubsystemHandler from paramiko.server import SubsystemHandler
from paramiko.sftp import *
from paramiko.sftp_si import *
from paramiko.sftp_attr import *
# known hash algorithms for the "check-file" extension # known hash algorithms for the "check-file" extension
from paramiko.sftp import CMD_HANDLE, SFTP_DESC, CMD_STATUS, SFTP_EOF, CMD_NAME, \
SFTP_BAD_MESSAGE, CMD_EXTENDED_REPLY, SFTP_FLAG_READ, SFTP_FLAG_WRITE, \
SFTP_FLAG_APPEND, SFTP_FLAG_CREATE, SFTP_FLAG_TRUNC, SFTP_FLAG_EXCL, \
CMD_NAMES, CMD_OPEN, CMD_CLOSE, SFTP_OK, CMD_READ, CMD_DATA, CMD_WRITE, \
CMD_REMOVE, CMD_RENAME, CMD_MKDIR, CMD_RMDIR, CMD_OPENDIR, CMD_READDIR, \
CMD_STAT, CMD_ATTRS, CMD_LSTAT, CMD_FSTAT, CMD_SETSTAT, CMD_FSETSTAT, \
CMD_READLINK, CMD_SYMLINK, CMD_REALPATH, CMD_EXTENDED, SFTP_OP_UNSUPPORTED
_hash_class = { _hash_class = {
'sha1': SHA, 'sha1': SHA,
'md5': MD5, 'md5': MD5,
@ -67,8 +79,8 @@ class SFTPServer (BaseSFTP, SubsystemHandler):
self.ultra_debug = transport.get_hexdump() self.ultra_debug = transport.get_hexdump()
self.next_handle = 1 self.next_handle = 1
# map of handle-string to SFTPHandle for files & folders: # map of handle-string to SFTPHandle for files & folders:
self.file_table = { } self.file_table = {}
self.folder_table = { } self.folder_table = {}
self.server = sftp_si(server, *largs, **kwargs) self.server = sftp_si(server, *largs, **kwargs)
def _log(self, level, msg): def _log(self, level, msg):
@ -163,10 +175,8 @@ class SFTPServer (BaseSFTP, SubsystemHandler):
f.truncate(attr.st_size) f.truncate(attr.st_size)
set_file_attr = staticmethod(set_file_attr) set_file_attr = staticmethod(set_file_attr)
### internals... ### internals...
def _response(self, request_number, t, *arg): def _response(self, request_number, t, *arg):
msg = Message() msg = Message()
msg.add_int(request_number) msg.add_int(request_number)
@ -290,7 +300,7 @@ class SFTPServer (BaseSFTP, SubsystemHandler):
self._send_packet(CMD_EXTENDED_REPLY, msg) self._send_packet(CMD_EXTENDED_REPLY, msg)
def _convert_pflags(self, pflags): def _convert_pflags(self, pflags):
"convert SFTP-style open() flags to Python's os.open() flags" """convert SFTP-style open() flags to Python's os.open() flags"""
if (pflags & SFTP_FLAG_READ) and (pflags & SFTP_FLAG_WRITE): if (pflags & SFTP_FLAG_READ) and (pflags & SFTP_FLAG_WRITE):
flags = os.O_RDWR flags = os.O_RDWR
elif pflags & SFTP_FLAG_WRITE: elif pflags & SFTP_FLAG_WRITE:

View File

@ -21,9 +21,8 @@ An interface to override for SFTP server support.
""" """
import os import os
import sys
from paramiko.common import * from paramiko.sftp import SFTP_OP_UNSUPPORTED
from paramiko.sftp import *
class SFTPServerInterface (object): class SFTPServerInterface (object):
@ -41,7 +40,7 @@ class SFTPServerInterface (object):
clients & servers obey the requirement that paths be encoded in UTF-8. clients & servers obey the requirement that paths be encoded in UTF-8.
""" """
def __init__ (self, server, *largs, **kwargs): def __init__(self, server, *largs, **kwargs):
""" """
Create a new SFTPServerInterface object. This method does nothing by Create a new SFTPServerInterface object. This method does nothing by
default and is meant to be overridden by subclasses. default and is meant to be overridden by subclasses.

View File

@ -20,10 +20,7 @@
Core protocol implementation Core protocol implementation
""" """
import os
import socket import socket
import string
import struct
import sys import sys
import threading import threading
import time import time
@ -33,7 +30,17 @@ import paramiko
from paramiko import util from paramiko import util
from paramiko.auth_handler import AuthHandler from paramiko.auth_handler import AuthHandler
from paramiko.channel import Channel from paramiko.channel import Channel
from paramiko.common import * # Legit, uses dozens of constants & funcs from paramiko.common import rng, xffffffff, cMSG_CHANNEL_OPEN, cMSG_IGNORE, \
cMSG_GLOBAL_REQUEST, DEBUG, MSG_KEXINIT, MSG_IGNORE, MSG_DISCONNECT, \
MSG_DEBUG, ERROR, WARNING, cMSG_UNIMPLEMENTED, INFO, cMSG_KEXINIT, \
cMSG_NEWKEYS, MSG_NEWKEYS, cMSG_REQUEST_SUCCESS, cMSG_REQUEST_FAILURE, \
CONNECTION_FAILED_CODE, OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED, \
OPEN_SUCCEEDED, cMSG_CHANNEL_OPEN_FAILURE, cMSG_CHANNEL_OPEN_SUCCESS, \
MSG_GLOBAL_REQUEST, MSG_REQUEST_SUCCESS, MSG_REQUEST_FAILURE, \
MSG_CHANNEL_OPEN_SUCCESS, MSG_CHANNEL_OPEN_FAILURE, MSG_CHANNEL_OPEN, \
MSG_CHANNEL_SUCCESS, MSG_CHANNEL_FAILURE, MSG_CHANNEL_DATA, \
MSG_CHANNEL_EXTENDED_DATA, MSG_CHANNEL_WINDOW_ADJUST, MSG_CHANNEL_REQUEST, \
MSG_CHANNEL_EOF, MSG_CHANNEL_CLOSE
from paramiko.compress import ZlibCompressor, ZlibDecompressor from paramiko.compress import ZlibCompressor, ZlibDecompressor
from paramiko.dsskey import DSSKey from paramiko.dsskey import DSSKey
from paramiko.kex_gex import KexGex from paramiko.kex_gex import KexGex
@ -41,12 +48,13 @@ from paramiko.kex_group1 import KexGroup1
from paramiko.message import Message from paramiko.message import Message
from paramiko.packet import Packetizer, NeedRekeyException from paramiko.packet import Packetizer, NeedRekeyException
from paramiko.primes import ModulusPack from paramiko.primes import ModulusPack
from paramiko.py3compat import string_types, long, byte_ord, b
from paramiko.rsakey import RSAKey from paramiko.rsakey import RSAKey
from paramiko.ecdsakey import ECDSAKey from paramiko.ecdsakey import ECDSAKey
from paramiko.server import ServerInterface from paramiko.server import ServerInterface
from paramiko.sftp_client import SFTPClient from paramiko.sftp_client import SFTPClient
from paramiko.ssh_exception import (SSHException, BadAuthenticationType, from paramiko.ssh_exception import (SSHException, BadAuthenticationType,
ChannelException, ProxyCommandFailure) ChannelException, ProxyCommandFailure)
from paramiko.util import retry_on_signal from paramiko.util import retry_on_signal
from Crypto import Random from Crypto import Random
@ -60,9 +68,11 @@ except ImportError:
# for thread cleanup # for thread cleanup
_active_threads = [] _active_threads = []
def _join_lingering_threads(): def _join_lingering_threads():
for thr in _active_threads: for thr in _active_threads:
thr.stop_thread() thr.stop_thread()
import atexit import atexit
atexit.register(_join_lingering_threads) atexit.register(_join_lingering_threads)
@ -76,54 +86,53 @@ class Transport (threading.Thread):
forwardings). forwardings).
""" """
_PROTO_ID = '2.0' _PROTO_ID = '2.0'
_CLIENT_ID = 'paramiko_%s' % (paramiko.__version__) _CLIENT_ID = 'paramiko_%s' % paramiko.__version__
_preferred_ciphers = ( 'aes128-ctr', 'aes256-ctr', 'aes128-cbc', 'blowfish-cbc', 'aes256-cbc', '3des-cbc', _preferred_ciphers = ('aes128-ctr', 'aes256-ctr', 'aes128-cbc', 'blowfish-cbc',
'arcfour128', 'arcfour256' ) 'aes256-cbc', '3des-cbc', 'arcfour128', 'arcfour256')
_preferred_macs = ( 'hmac-sha1', 'hmac-md5', 'hmac-sha1-96', 'hmac-md5-96' ) _preferred_macs = ('hmac-sha1', 'hmac-md5', 'hmac-sha1-96', 'hmac-md5-96')
_preferred_keys = ( 'ssh-rsa', 'ssh-dss', 'ecdsa-sha2-nistp256' ) _preferred_keys = ('ssh-rsa', 'ssh-dss', 'ecdsa-sha2-nistp256')
_preferred_kex = ( 'diffie-hellman-group1-sha1', 'diffie-hellman-group-exchange-sha1' ) _preferred_kex = ('diffie-hellman-group1-sha1', 'diffie-hellman-group-exchange-sha1')
_preferred_compression = ( 'none', ) _preferred_compression = ('none',)
_cipher_info = { _cipher_info = {
'aes128-ctr': { 'class': AES, 'mode': AES.MODE_CTR, 'block-size': 16, 'key-size': 16 }, 'aes128-ctr': {'class': AES, 'mode': AES.MODE_CTR, 'block-size': 16, 'key-size': 16},
'aes256-ctr': { 'class': AES, 'mode': AES.MODE_CTR, 'block-size': 16, 'key-size': 32 }, 'aes256-ctr': {'class': AES, 'mode': AES.MODE_CTR, 'block-size': 16, 'key-size': 32},
'blowfish-cbc': { 'class': Blowfish, 'mode': Blowfish.MODE_CBC, 'block-size': 8, 'key-size': 16 }, 'blowfish-cbc': {'class': Blowfish, 'mode': Blowfish.MODE_CBC, 'block-size': 8, 'key-size': 16},
'aes128-cbc': { 'class': AES, 'mode': AES.MODE_CBC, 'block-size': 16, 'key-size': 16 }, 'aes128-cbc': {'class': AES, 'mode': AES.MODE_CBC, 'block-size': 16, 'key-size': 16},
'aes256-cbc': { 'class': AES, 'mode': AES.MODE_CBC, 'block-size': 16, 'key-size': 32 }, 'aes256-cbc': {'class': AES, 'mode': AES.MODE_CBC, 'block-size': 16, 'key-size': 32},
'3des-cbc': { 'class': DES3, 'mode': DES3.MODE_CBC, 'block-size': 8, 'key-size': 24 }, '3des-cbc': {'class': DES3, 'mode': DES3.MODE_CBC, 'block-size': 8, 'key-size': 24},
'arcfour128': { 'class': ARC4, 'mode': None, 'block-size': 8, 'key-size': 16 }, 'arcfour128': {'class': ARC4, 'mode': None, 'block-size': 8, 'key-size': 16},
'arcfour256': { 'class': ARC4, 'mode': None, 'block-size': 8, 'key-size': 32 }, 'arcfour256': {'class': ARC4, 'mode': None, 'block-size': 8, 'key-size': 32},
} }
_mac_info = { _mac_info = {
'hmac-sha1': { 'class': SHA, 'size': 20 }, 'hmac-sha1': {'class': SHA, 'size': 20},
'hmac-sha1-96': { 'class': SHA, 'size': 12 }, 'hmac-sha1-96': {'class': SHA, 'size': 12},
'hmac-md5': { 'class': MD5, 'size': 16 }, 'hmac-md5': {'class': MD5, 'size': 16},
'hmac-md5-96': { 'class': MD5, 'size': 12 }, 'hmac-md5-96': {'class': MD5, 'size': 12},
} }
_key_info = { _key_info = {
'ssh-rsa': RSAKey, 'ssh-rsa': RSAKey,
'ssh-dss': DSSKey, 'ssh-dss': DSSKey,
'ecdsa-sha2-nistp256': ECDSAKey, 'ecdsa-sha2-nistp256': ECDSAKey,
} }
_kex_info = { _kex_info = {
'diffie-hellman-group1-sha1': KexGroup1, 'diffie-hellman-group1-sha1': KexGroup1,
'diffie-hellman-group-exchange-sha1': KexGex, 'diffie-hellman-group-exchange-sha1': KexGex,
} }
_compression_info = { _compression_info = {
# zlib@openssh.com is just zlib, but only turned on after a successful # zlib@openssh.com is just zlib, but only turned on after a successful
# authentication. openssh servers may only offer this type because # authentication. openssh servers may only offer this type because
# they've had troubles with security holes in zlib in the past. # they've had troubles with security holes in zlib in the past.
'zlib@openssh.com': ( ZlibCompressor, ZlibDecompressor ), 'zlib@openssh.com': (ZlibCompressor, ZlibDecompressor),
'zlib': ( ZlibCompressor, ZlibDecompressor ), 'zlib': (ZlibCompressor, ZlibDecompressor),
'none': ( None, None ), 'none': (None, None),
} }
_modulus_pack = None _modulus_pack = None
def __init__(self, sock): def __init__(self, sock):
@ -220,8 +229,8 @@ class Transport (threading.Thread):
# tracking open channels # tracking open channels
self._channels = ChannelMap() self._channels = ChannelMap()
self.channel_events = { } # (id -> Event) self.channel_events = {} # (id -> Event)
self.channels_seen = { } # (id -> True) self.channels_seen = {} # (id -> True)
self._channel_counter = 1 self._channel_counter = 1
self.window_size = 65536 self.window_size = 65536
self.max_packet_size = 34816 self.max_packet_size = 34816
@ -244,10 +253,10 @@ class Transport (threading.Thread):
# server mode: # server mode:
self.server_mode = False self.server_mode = False
self.server_object = None self.server_object = None
self.server_key_dict = { } self.server_key_dict = {}
self.server_accepts = [ ] self.server_accepts = []
self.server_accept_cv = threading.Condition(self.lock) self.server_accept_cv = threading.Condition(self.lock)
self.subsystem_table = { } self.subsystem_table = {}
def __repr__(self): def __repr__(self):
""" """
@ -468,7 +477,7 @@ class Transport (threading.Thread):
""" """
Transport._modulus_pack = ModulusPack(rng) Transport._modulus_pack = ModulusPack(rng)
# places to look for the openssh "moduli" file # places to look for the openssh "moduli" file
file_list = [ '/etc/ssh/moduli', '/usr/local/etc/moduli' ] file_list = ['/etc/ssh/moduli', '/usr/local/etc/moduli']
if filename is not None: if filename is not None:
file_list.insert(0, filename) file_list.insert(0, filename)
for fn in file_list: for fn in file_list:
@ -623,7 +632,7 @@ class Transport (threading.Thread):
self.lock.release() self.lock.release()
self._send_user_message(m) self._send_user_message(m)
while True: while True:
event.wait(0.1); event.wait(0.1)
if not self.active: if not self.active:
e = self.get_exception() e = self.get_exception()
if e is None: if e is None:
@ -764,7 +773,7 @@ class Transport (threading.Thread):
0 to disable keepalives). 0 to disable keepalives).
""" """
self.packetizer.set_keepalive(interval, self.packetizer.set_keepalive(interval,
lambda x=weakref.proxy(self): x.global_request('keepalive@lag.net', wait=False)) lambda x=weakref.proxy(self): x.global_request('keepalive@lag.net', wait=False))
def global_request(self, kind, data=None, wait=True): def global_request(self, kind, data=None, wait=True):
""" """
@ -863,12 +872,12 @@ class Transport (threading.Thread):
supplied by the server is incorrect, or authentication fails. supplied by the server is incorrect, or authentication fails.
""" """
if hostkey is not None: if hostkey is not None:
self._preferred_keys = [ hostkey.get_name() ] self._preferred_keys = [hostkey.get_name()]
self.start_client() self.start_client()
# check host key if we were given one # check host key if we were given one
if (hostkey is not None): if hostkey is not None:
key = self.get_remote_server_key() key = self.get_remote_server_key()
if (key.get_name() != hostkey.get_name()) or (key.asbytes() != hostkey.asbytes()): if (key.get_name() != hostkey.get_name()) or (key.asbytes() != hostkey.asbytes()):
self._log(DEBUG, 'Bad host key from server') self._log(DEBUG, 'Bad host key from server')
@ -1061,12 +1070,11 @@ class Transport (threading.Thread):
# to try to fake out automated scripting of the exact # to try to fake out automated scripting of the exact
# type we're doing here. *shrug* :) # type we're doing here. *shrug* :)
return [] return []
return [ password ] return [password]
return self.auth_interactive(username, handler) return self.auth_interactive(username, handler)
except SSHException: except SSHException:
# attempt failed; just raise the original exception # attempt failed; just raise the original exception
raise e raise e
return None
def auth_publickey(self, username, key, event=None): def auth_publickey(self, username, key, event=None):
""" """
@ -1227,9 +1235,9 @@ class Transport (threading.Thread):
.. versionadded:: 1.5.2 .. versionadded:: 1.5.2
""" """
if compress: if compress:
self._preferred_compression = ( 'zlib@openssh.com', 'zlib', 'none' ) self._preferred_compression = ('zlib@openssh.com', 'zlib', 'none')
else: else:
self._preferred_compression = ( 'none', ) self._preferred_compression = ('none',)
def getpeername(self): def getpeername(self):
""" """
@ -1244,7 +1252,7 @@ class Transport (threading.Thread):
""" """
gp = getattr(self.sock, 'getpeername', None) gp = getattr(self.sock, 'getpeername', None)
if gp is None: if gp is None:
return ('unknown', 0) return 'unknown', 0
return gp() return gp()
def stop_thread(self): def stop_thread(self):
@ -1253,10 +1261,8 @@ class Transport (threading.Thread):
while self.isAlive(): while self.isAlive():
self.join(10) self.join(10)
### internals... ### internals...
def _log(self, level, msg, *args): def _log(self, level, msg, *args):
if issubclass(type(msg), list): if issubclass(type(msg), list):
for m in msg: for m in msg:
@ -1265,11 +1271,11 @@ class Transport (threading.Thread):
self.logger.log(level, msg, *args) self.logger.log(level, msg, *args)
def _get_modulus_pack(self): def _get_modulus_pack(self):
"used by KexGex to find primes for group exchange" """used by KexGex to find primes for group exchange"""
return self._modulus_pack return self._modulus_pack
def _next_channel(self): def _next_channel(self):
"you are holding the lock" """you are holding the lock"""
chanid = self._channel_counter chanid = self._channel_counter
while self._channels.get(chanid) is not None: while self._channels.get(chanid) is not None:
self._channel_counter = (self._channel_counter + 1) & 0xffffff self._channel_counter = (self._channel_counter + 1) & 0xffffff
@ -1278,7 +1284,7 @@ class Transport (threading.Thread):
return chanid return chanid
def _unlink_channel(self, chanid): def _unlink_channel(self, chanid):
"used by a Channel to remove itself from the active channel list" """used by a Channel to remove itself from the active channel list"""
self._channels.delete(chanid) self._channels.delete(chanid)
def _send_message(self, data): def _send_message(self, data):
@ -1307,14 +1313,14 @@ class Transport (threading.Thread):
self.clear_to_send_lock.release() self.clear_to_send_lock.release()
def _set_K_H(self, k, h): def _set_K_H(self, k, h):
"used by a kex object to set the K (root key) and H (exchange hash)" """used by a kex object to set the K (root key) and H (exchange hash)"""
self.K = k self.K = k
self.H = h self.H = h
if self.session_id == None: if self.session_id is None:
self.session_id = h self.session_id = h
def _expect_packet(self, *ptypes): def _expect_packet(self, *ptypes):
"used by a kex object to register the next packet type it expects to see" """used by a kex object to register the next packet type it expects to see"""
self._expected_packet = tuple(ptypes) self._expected_packet = tuple(ptypes)
def _verify_key(self, host_key, sig): def _verify_key(self, host_key, sig):
@ -1326,7 +1332,7 @@ class Transport (threading.Thread):
self.host_key = key self.host_key = key
def _compute_key(self, id, nbytes): def _compute_key(self, id, nbytes):
"id is 'A' - 'F' for the various keys used by ssh" """id is 'A' - 'F' for the various keys used by ssh"""
m = Message() m = Message()
m.add_mpint(self.K) m.add_mpint(self.K)
m.add_bytes(self.H) m.add_bytes(self.H)
@ -1471,7 +1477,7 @@ class Transport (threading.Thread):
if type(e.args) is tuple: if type(e.args) is tuple:
if e.args: if e.args:
emsg = '%s (%d)' % (e.args[1], e.args[0]) emsg = '%s (%d)' % (e.args[1], e.args[0])
else: # empty tuple, e.g. socket.timeout else: # empty tuple, e.g. socket.timeout
emsg = str(e) or repr(e) emsg = str(e) or repr(e)
else: else:
emsg = e.args emsg = e.args
@ -1487,7 +1493,7 @@ class Transport (threading.Thread):
if self.active: if self.active:
self.active = False self.active = False
self.packetizer.close() self.packetizer.close()
if self.completion_event != None: if self.completion_event is not None:
self.completion_event.set() self.completion_event.set()
if self.auth_handler is not None: if self.auth_handler is not None:
self.auth_handler.abort() self.auth_handler.abort()
@ -1507,10 +1513,8 @@ class Transport (threading.Thread):
if self.sys.modules is not None: if self.sys.modules is not None:
raise raise
### protocol stages ### protocol stages
def _negotiate_keys(self, m): def _negotiate_keys(self, m):
# throws SSHException on anything unusual # throws SSHException on anything unusual
self.clear_to_send_lock.acquire() self.clear_to_send_lock.acquire()
@ -1518,7 +1522,7 @@ class Transport (threading.Thread):
self.clear_to_send.clear() self.clear_to_send.clear()
finally: finally:
self.clear_to_send_lock.release() self.clear_to_send_lock.release()
if self.local_kex_init == None: if self.local_kex_init is None:
# remote side wants to renegotiate # remote side wants to renegotiate
self._send_kex_init() self._send_kex_init()
self._parse_kex_init(m) self._parse_kex_init(m)
@ -1580,7 +1584,7 @@ class Transport (threading.Thread):
pkex.remove('diffie-hellman-group-exchange-sha1') pkex.remove('diffie-hellman-group-exchange-sha1')
self.get_security_options().kex = pkex self.get_security_options().kex = pkex
available_server_keys = list(filter(list(self.server_key_dict.keys()).__contains__, available_server_keys = list(filter(list(self.server_key_dict.keys()).__contains__,
self._preferred_keys)) self._preferred_keys))
else: else:
available_server_keys = self._preferred_keys available_server_keys = self._preferred_keys
@ -1618,15 +1622,15 @@ class Transport (threading.Thread):
kex_follows = m.get_boolean() kex_follows = m.get_boolean()
unused = m.get_int() unused = m.get_int()
self._log(DEBUG, 'kex algos:' + str(kex_algo_list) + ' server key:' + str(server_key_algo_list) + \ self._log(DEBUG, 'kex algos:' + str(kex_algo_list) + ' server key:' + str(server_key_algo_list) +
' client encrypt:' + str(client_encrypt_algo_list) + \ ' client encrypt:' + str(client_encrypt_algo_list) +
' server encrypt:' + str(server_encrypt_algo_list) + \ ' server encrypt:' + str(server_encrypt_algo_list) +
' client mac:' + str(client_mac_algo_list) + \ ' client mac:' + str(client_mac_algo_list) +
' server mac:' + str(server_mac_algo_list) + \ ' server mac:' + str(server_mac_algo_list) +
' client compress:' + str(client_compress_algo_list) + \ ' client compress:' + str(client_compress_algo_list) +
' server compress:' + str(server_compress_algo_list) + \ ' server compress:' + str(server_compress_algo_list) +
' client lang:' + str(client_lang_list) + \ ' client lang:' + str(client_lang_list) +
' server lang:' + str(server_lang_list) + \ ' server lang:' + str(server_lang_list) +
' kex follows?' + str(kex_follows)) ' kex follows?' + str(kex_follows))
# as a server, we pick the first item in the client's list that we support. # as a server, we pick the first item in the client's list that we support.
@ -1641,7 +1645,7 @@ class Transport (threading.Thread):
if self.server_mode: if self.server_mode:
available_server_keys = list(filter(list(self.server_key_dict.keys()).__contains__, available_server_keys = list(filter(list(self.server_key_dict.keys()).__contains__,
self._preferred_keys)) self._preferred_keys))
agreed_keys = list(filter(available_server_keys.__contains__, server_key_algo_list)) agreed_keys = list(filter(available_server_keys.__contains__, server_key_algo_list))
else: else:
agreed_keys = list(filter(server_key_algo_list.__contains__, self._preferred_keys)) agreed_keys = list(filter(server_key_algo_list.__contains__, self._preferred_keys))
@ -1701,7 +1705,7 @@ class Transport (threading.Thread):
self.remote_kex_init = cMSG_KEXINIT + m.get_so_far() self.remote_kex_init = cMSG_KEXINIT + m.get_so_far()
def _activate_inbound(self): def _activate_inbound(self):
"switch on newly negotiated encryption parameters for inbound traffic" """switch on newly negotiated encryption parameters for inbound traffic"""
block_size = self._cipher_info[self.remote_cipher]['block-size'] block_size = self._cipher_info[self.remote_cipher]['block-size']
if self.server_mode: if self.server_mode:
IV_in = self._compute_key('A', block_size) IV_in = self._compute_key('A', block_size)
@ -1725,7 +1729,7 @@ class Transport (threading.Thread):
self.packetizer.set_inbound_compressor(compress_in()) self.packetizer.set_inbound_compressor(compress_in())
def _activate_outbound(self): def _activate_outbound(self):
"switch on newly negotiated encryption parameters for outbound traffic" """switch on newly negotiated encryption parameters for outbound traffic"""
m = Message() m = Message()
m.add_byte(cMSG_NEWKEYS) m.add_byte(cMSG_NEWKEYS)
self._send_message(m) self._send_message(m)
@ -1782,7 +1786,7 @@ class Transport (threading.Thread):
# this was the first key exchange # this was the first key exchange
self.initial_kex_done = True self.initial_kex_done = True
# send an event? # send an event?
if self.completion_event != None: if self.completion_event is not None:
self.completion_event.set() self.completion_event.set()
# it's now okay to send data again (if this was a re-key) # it's now okay to send data again (if this was a re-key)
if not self.packetizer.need_rekey(): if not self.packetizer.need_rekey():
@ -1810,7 +1814,7 @@ class Transport (threading.Thread):
address = m.get_text() address = m.get_text()
port = m.get_int() port = m.get_int()
ok = self.server_object.check_port_forward_request(address, port) ok = self.server_object.check_port_forward_request(address, port)
if ok != False: if ok:
ok = (ok,) ok = (ok,)
elif kind == 'cancel-tcpip-forward': elif kind == 'cancel-tcpip-forward':
address = m.get_text() address = m.get_text()
@ -1933,8 +1937,7 @@ class Transport (threading.Thread):
origin_addr = m.get_text() origin_addr = m.get_text()
origin_port = m.get_int() origin_port = m.get_int()
reason = self.server_object.check_channel_direct_tcpip_request( reason = self.server_object.check_channel_direct_tcpip_request(
my_chanid, (origin_addr, origin_port), my_chanid, (origin_addr, origin_port), (dest_addr, dest_port))
(dest_addr, dest_port))
else: else:
reason = self.server_object.check_channel_request(kind, my_chanid) reason = self.server_object.check_channel_request(kind, my_chanid)
if reason != OPEN_SUCCEEDED: if reason != OPEN_SUCCEEDED:
@ -1988,7 +1991,7 @@ class Transport (threading.Thread):
try: try:
self.lock.acquire() self.lock.acquire()
if name not in self.subsystem_table: if name not in self.subsystem_table:
return (None, [], {}) return None, [], {}
return self.subsystem_table[name] return self.subsystem_table[name]
finally: finally:
self.lock.release() self.lock.release()
@ -2002,7 +2005,7 @@ class Transport (threading.Thread):
MSG_CHANNEL_OPEN_FAILURE: _parse_channel_open_failure, MSG_CHANNEL_OPEN_FAILURE: _parse_channel_open_failure,
MSG_CHANNEL_OPEN: _parse_channel_open, MSG_CHANNEL_OPEN: _parse_channel_open,
MSG_KEXINIT: _negotiate_keys, MSG_KEXINIT: _negotiate_keys,
} }
_channel_handler_table = { _channel_handler_table = {
MSG_CHANNEL_SUCCESS: Channel._request_success, MSG_CHANNEL_SUCCESS: Channel._request_success,
@ -2013,7 +2016,7 @@ class Transport (threading.Thread):
MSG_CHANNEL_REQUEST: Channel._handle_request, MSG_CHANNEL_REQUEST: Channel._handle_request,
MSG_CHANNEL_EOF: Channel._handle_eof, MSG_CHANNEL_EOF: Channel._handle_eof,
MSG_CHANNEL_CLOSE: Channel._handle_close, MSG_CHANNEL_CLOSE: Channel._handle_close,
} }
class SecurityOptions (object): class SecurityOptions (object):

View File

@ -29,25 +29,15 @@ import sys
import struct import struct
import traceback import traceback
import threading import threading
import logging
from paramiko.common import PY2, DEBUG, long, zero_byte, byte_ord, xffffffff, logging, b, max_byte from paramiko.common import DEBUG, zero_byte, xffffffff, max_byte
from paramiko.py3compat import PY2, long, byte_ord, b, byte_chr
from paramiko.config import SSHConfig from paramiko.config import SSHConfig
# Change by RogerB - Python < 2.3 doesn't have enumerate so we implement it
if sys.version_info < (2,3):
class enumerate:
def __init__ (self, sequence):
self.sequence = sequence
def __iter__ (self):
count = 0
for item in self.sequence:
yield (count, item)
count += 1
def inflate_long(s, always_positive=False): def inflate_long(s, always_positive=False):
"turns a normalized byte string into a long-int (adapted from Crypto.Util.number)" """turns a normalized byte string into a long-int (adapted from Crypto.Util.number)"""
out = long(0) out = long(0)
negative = 0 negative = 0
if not always_positive and (len(s) > 0) and (byte_ord(s[0]) >= 0x80): if not always_positive and (len(s) > 0) and (byte_ord(s[0]) >= 0x80):
@ -56,6 +46,8 @@ def inflate_long(s, always_positive=False):
filler = zero_byte filler = zero_byte
if negative: if negative:
filler = max_byte filler = max_byte
# never convert this to ``s +=`` because this is a string, not a number
# noinspection PyAugmentAssignment
s = filler * (4 - len(s) % 4) + s s = filler * (4 - len(s) % 4) + s
for i in range(0, len(s), 4): for i in range(0, len(s), 4):
out = (out << 32) + struct.unpack('>I', s[i:i+4])[0] out = (out << 32) + struct.unpack('>I', s[i:i+4])[0]
@ -66,14 +58,15 @@ def inflate_long(s, always_positive=False):
deflate_zero = zero_byte if PY2 else 0 deflate_zero = zero_byte if PY2 else 0
deflate_ff = max_byte if PY2 else 0xff deflate_ff = max_byte if PY2 else 0xff
def deflate_long(n, add_sign_padding=True): def deflate_long(n, add_sign_padding=True):
"turns a long-int into a normalized byte string (adapted from Crypto.Util.number)" """turns a long-int into a normalized byte string (adapted from Crypto.Util.number)"""
# after much testing, this algorithm was deemed to be the fastest # after much testing, this algorithm was deemed to be the fastest
s = bytes() s = bytes()
n = long(n) n = long(n)
while (n != 0) and (n != -1): while (n != 0) and (n != -1):
s = struct.pack('>I', n & xffffffff) + s s = struct.pack('>I', n & xffffffff) + s
n = n >> 32 n >>= 32
# strip off leading zeros, FFs # strip off leading zeros, FFs
for i in enumerate(s): for i in enumerate(s):
if (n == 0) and (i[1] != deflate_zero): if (n == 0) and (i[1] != deflate_zero):
@ -95,6 +88,7 @@ def deflate_long(n, add_sign_padding=True):
s = max_byte + s s = max_byte + s
return s return s
def format_binary(data, prefix=''): def format_binary(data, prefix=''):
x = 0 x = 0
out = [] out = []
@ -105,17 +99,21 @@ def format_binary(data, prefix=''):
out.append(format_binary_line(data[x:])) out.append(format_binary_line(data[x:]))
return [prefix + x for x in out] return [prefix + x for x in out]
def format_binary_line(data): def format_binary_line(data):
left = ' '.join(['%02X' % byte_ord(c) for c in data]) left = ' '.join(['%02X' % byte_ord(c) for c in data])
right = ''.join([('.%c..' % c)[(byte_ord(c)+63)//95] for c in data]) right = ''.join([('.%c..' % c)[(byte_ord(c)+63)//95] for c in data])
return '%-50s %s' % (left, right) return '%-50s %s' % (left, right)
def hexify(s): def hexify(s):
return hexlify(s).upper() return hexlify(s).upper()
def unhexify(s): def unhexify(s):
return unhexlify(s) return unhexlify(s)
def safe_string(s): def safe_string(s):
out = '' out = ''
for c in s: for c in s:
@ -125,13 +123,12 @@ def safe_string(s):
out += '%%%02X' % byte_ord(c) out += '%%%02X' % byte_ord(c)
return out return out
# ''.join([['%%%02X' % ord(c), c][(ord(c) >= 32) and (ord(c) <= 127)] for c in s])
def bit_length(n): def bit_length(n):
try: try:
return n.bitlength() return n.bitlength()
except AttributeError: except AttributeError:
norm = deflate_long(n, 0) norm = deflate_long(n, False)
hbyte = byte_ord(norm[0]) hbyte = byte_ord(norm[0])
if hbyte == 0: if hbyte == 0:
return 1 return 1
@ -141,9 +138,11 @@ def bit_length(n):
bitlen -= 1 bitlen -= 1
return bitlen return bitlen
def tb_strings(): def tb_strings():
return ''.join(traceback.format_exception(*sys.exc_info())).split('\n') return ''.join(traceback.format_exception(*sys.exc_info())).split('\n')
def generate_key_bytes(hashclass, salt, key, nbytes): def generate_key_bytes(hashclass, salt, key, nbytes):
""" """
Given a password, passphrase, or other human-source key, scramble it Given a password, passphrase, or other human-source key, scramble it
@ -175,6 +174,7 @@ def generate_key_bytes(hashclass, salt, key, nbytes):
nbytes -= size nbytes -= size
return keydata return keydata
def load_host_keys(filename): def load_host_keys(filename):
""" """
Read a file of known SSH host keys, in the format used by openssh, and Read a file of known SSH host keys, in the format used by openssh, and
@ -194,6 +194,7 @@ def load_host_keys(filename):
from paramiko.hostkeys import HostKeys from paramiko.hostkeys import HostKeys
return HostKeys(filename) return HostKeys(filename)
def parse_ssh_config(file_obj): def parse_ssh_config(file_obj):
""" """
Provided only as a backward-compatible wrapper around `.SSHConfig`. Provided only as a backward-compatible wrapper around `.SSHConfig`.
@ -202,12 +203,14 @@ def parse_ssh_config(file_obj):
config.parse(file_obj) config.parse(file_obj)
return config return config
def lookup_ssh_host_config(hostname, config): def lookup_ssh_host_config(hostname, config):
""" """
Provided only as a backward-compatible wrapper around `.SSHConfig`. Provided only as a backward-compatible wrapper around `.SSHConfig`.
""" """
return config.lookup(hostname) return config.lookup(hostname)
def mod_inverse(x, m): def mod_inverse(x, m):
# it's crazy how small Python can make this function. # it's crazy how small Python can make this function.
u1, u2, u3 = 1, 0, m u1, u2, u3 = 1, 0, m
@ -225,6 +228,8 @@ def mod_inverse(x, m):
_g_thread_ids = {} _g_thread_ids = {}
_g_thread_counter = 0 _g_thread_counter = 0
_g_thread_lock = threading.Lock() _g_thread_lock = threading.Lock()
def get_thread_id(): def get_thread_id():
global _g_thread_ids, _g_thread_counter, _g_thread_lock global _g_thread_ids, _g_thread_counter, _g_thread_lock
tid = id(threading.currentThread()) tid = id(threading.currentThread())
@ -239,8 +244,9 @@ def get_thread_id():
_g_thread_lock.release() _g_thread_lock.release()
return ret return ret
def log_to_file(filename, level=DEBUG): def log_to_file(filename, level=DEBUG):
"send paramiko logs to a logfile, if they're not already going somewhere" """send paramiko logs to a logfile, if they're not already going somewhere"""
l = logging.getLogger("paramiko") l = logging.getLogger("paramiko")
if len(l.handlers) > 0: if len(l.handlers) > 0:
return return
@ -251,6 +257,7 @@ def log_to_file(filename, level=DEBUG):
'%Y%m%d-%H:%M:%S')) '%Y%m%d-%H:%M:%S'))
l.addHandler(lh) l.addHandler(lh)
# make only one filter object, so it doesn't get applied more than once # make only one filter object, so it doesn't get applied more than once
class PFilter (object): class PFilter (object):
def filter(self, record): def filter(self, record):
@ -258,11 +265,13 @@ class PFilter (object):
return True return True
_pfilter = PFilter() _pfilter = PFilter()
def get_logger(name): def get_logger(name):
l = logging.getLogger(name) l = logging.getLogger(name)
l.addFilter(_pfilter) l.addFilter(_pfilter)
return l return l
def retry_on_signal(function): def retry_on_signal(function):
"""Retries function until it doesn't raise an EINTR error""" """Retries function until it doesn't raise an EINTR error"""
while True: while True:
@ -272,6 +281,7 @@ def retry_on_signal(function):
if e.errno != errno.EINTR: if e.errno != errno.EINTR:
raise raise
class Counter (object): class Counter (object):
"""Stateful counter for CTR mode crypto""" """Stateful counter for CTR mode crypto"""
def __init__(self, nbits, initial_value=long(1), overflow=long(0)): def __init__(self, nbits, initial_value=long(1), overflow=long(0)):
@ -307,6 +317,7 @@ def constant_time_bytes_eq(a, b):
if len(a) != len(b): if len(a) != len(b):
return False return False
res = 0 res = 0
# noinspection PyUnresolvedReferences
for i in (xrange if PY2 else range)(len(a)): for i in (xrange if PY2 else range)(len(a)):
res |= byte_ord(a[i]) ^ byte_ord(b[i]) res |= byte_ord(a[i]) ^ byte_ord(b[i])
return res == 0 return res == 0

View File

@ -21,7 +21,6 @@ A stub SFTP server for loopback SFTP testing.
""" """
import os import os
import sys
from paramiko import ServerInterface, SFTPServerInterface, SFTPServer, SFTPAttributes, \ from paramiko import ServerInterface, SFTPServerInterface, SFTPServer, SFTPAttributes, \
SFTPHandle, SFTP_OK, AUTH_SUCCESSFUL, OPEN_SUCCEEDED SFTPHandle, SFTP_OK, AUTH_SUCCESSFUL, OPEN_SUCCEEDED
from paramiko.common import o666 from paramiko.common import o666
@ -64,7 +63,7 @@ class StubSFTPServer (SFTPServerInterface):
def list_folder(self, path): def list_folder(self, path):
path = self._realpath(path) path = self._realpath(path)
try: try:
out = [ ] out = []
flist = os.listdir(path) flist = os.listdir(path)
for fname in flist: for fname in flist:
attr = SFTPAttributes.from_stat(os.stat(os.path.join(path, fname))) attr = SFTPAttributes.from_stat(os.stat(os.path.join(path, fname)))
@ -91,7 +90,7 @@ class StubSFTPServer (SFTPServerInterface):
def open(self, path, flags, attr): def open(self, path, flags, attr):
path = self._realpath(path) path = self._realpath(path)
try: try:
binary_flag = getattr(os, 'O_BINARY', 0) binary_flag = getattr(os, 'O_BINARY', 0)
flags |= binary_flag flags |= binary_flag
mode = getattr(attr, 'st_mode', None) mode = getattr(attr, 'st_mode', None)
if mode is not None: if mode is not None:

View File

@ -25,10 +25,9 @@ import threading
import unittest import unittest
from paramiko import Transport, ServerInterface, RSAKey, DSSKey, \ from paramiko import Transport, ServerInterface, RSAKey, DSSKey, \
SSHException, BadAuthenticationType, InteractiveQuery, ChannelException, \ BadAuthenticationType, InteractiveQuery, \
AuthenticationException AuthenticationException
from paramiko import AUTH_FAILED, AUTH_PARTIALLY_SUCCESSFUL, AUTH_SUCCESSFUL from paramiko import AUTH_FAILED, AUTH_PARTIALLY_SUCCESSFUL, AUTH_SUCCESSFUL
from paramiko import OPEN_SUCCEEDED, OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED
from paramiko.py3compat import u from paramiko.py3compat import u
from tests.loop import LoopSocket from tests.loop import LoopSocket
from tests.util import test_path from tests.util import test_path

View File

@ -22,24 +22,22 @@ Some unit tests for BufferedPipe.
import threading import threading
import time import time
import unittest
from paramiko.buffered_pipe import BufferedPipe, PipeTimeout from paramiko.buffered_pipe import BufferedPipe, PipeTimeout
from paramiko import pipe from paramiko import pipe
from paramiko.py3compat import b
from tests.util import ParamikoTest from tests.util import ParamikoTest
def delay_thread(pipe): def delay_thread(p):
pipe.feed('a') p.feed('a')
time.sleep(0.5) time.sleep(0.5)
pipe.feed('b') p.feed('b')
pipe.close() p.close()
def close_thread(pipe): def close_thread(p):
time.sleep(0.2) time.sleep(0.2)
pipe.close() p.close()
class BufferedPipeTest(ParamikoTest): class BufferedPipeTest(ParamikoTest):
@ -91,4 +89,3 @@ class BufferedPipeTest(ParamikoTest):
self.assertTrue(p._set) self.assertTrue(p._set)
p2.clear() p2.clear()
self.assertFalse(p._set) self.assertFalse(p._set)

View File

@ -158,7 +158,7 @@ class SSHClientTest (unittest.TestCase):
self.tc = paramiko.SSHClient() self.tc = paramiko.SSHClient()
self.tc.get_host_keys().add('[%s]:%d' % (self.addr, self.port), 'ssh-rsa', public_host_key) self.tc.get_host_keys().add('[%s]:%d' % (self.addr, self.port), 'ssh-rsa', public_host_key)
self.tc.connect(self.addr, self.port, username='slowdive', key_filename=[ test_path('test_rsa.key'), test_path('test_dss.key') ]) self.tc.connect(self.addr, self.port, username='slowdive', key_filename=[test_path('test_rsa.key'), test_path('test_dss.key')])
self.event.wait(1.0) self.event.wait(1.0)
self.assertTrue(self.event.isSet()) self.assertTrue(self.event.isSet())

View File

@ -20,12 +20,11 @@
Some unit tests for HostKeys. Some unit tests for HostKeys.
""" """
import base64
from binascii import hexlify from binascii import hexlify
import os import os
import unittest import unittest
import paramiko import paramiko
from paramiko.py3compat import b, decodebytes from paramiko.py3compat import decodebytes
test_hosts_file = """\ test_hosts_file = """\

View File

@ -37,8 +37,10 @@ class FakeRng (object):
class FakeKey (object): class FakeKey (object):
def __str__(self): def __str__(self):
return 'fake-key' return 'fake-key'
def asbytes(self): def asbytes(self):
return b'fake-key' return b'fake-key'
def sign_ssh_data(self, rng, H): def sign_ssh_data(self, rng, H):
return b'fake-sig' return b'fake-sig'
@ -46,6 +48,7 @@ class FakeKey (object):
class FakeModulusPack (object): class FakeModulusPack (object):
P = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF P = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF
G = 2 G = 2
def get_modulus(self, min, ask, max): def get_modulus(self, min, ask, max):
return self.G, self.P return self.G, self.P
@ -59,19 +62,26 @@ class FakeTransport (object):
def _send_message(self, m): def _send_message(self, m):
self._message = m self._message = m
def _expect_packet(self, *t): def _expect_packet(self, *t):
self._expect = t self._expect = t
def _set_K_H(self, K, H): def _set_K_H(self, K, H):
self._K = K self._K = K
self._H = H self._H = H
def _verify_key(self, host_key, sig): def _verify_key(self, host_key, sig):
self._verify = (host_key, sig) self._verify = (host_key, sig)
def _activate_outbound(self): def _activate_outbound(self):
self._activated = True self._activated = True
def _log(self, level, s): def _log(self, level, s):
pass pass
def get_server_key(self): def get_server_key(self):
return FakeKey() return FakeKey()
def _get_modulus_pack(self): def _get_modulus_pack(self):
return FakeModulusPack() return FakeModulusPack()

View File

@ -23,7 +23,7 @@ Some unit tests for the ssh2 protocol in Transport.
import unittest import unittest
from tests.loop import LoopSocket from tests.loop import LoopSocket
from Crypto.Cipher import AES from Crypto.Cipher import AES
from Crypto.Hash import SHA, HMAC from Crypto.Hash import SHA
from paramiko import Message, Packetizer, util from paramiko import Message, Packetizer, util
from paramiko.common import byte_chr, zero_byte from paramiko.common import byte_chr, zero_byte
@ -33,7 +33,7 @@ x1f = byte_chr(0x1f)
class PacketizerTest (unittest.TestCase): class PacketizerTest (unittest.TestCase):
def test_1_write (self): def test_1_write(self):
rsock = LoopSocket() rsock = LoopSocket()
wsock = LoopSocket() wsock = LoopSocket()
rsock.link(wsock) rsock.link(wsock)
@ -56,7 +56,7 @@ class PacketizerTest (unittest.TestCase):
self.assertEqual(44, len(data)) self.assertEqual(44, len(data))
self.assertEqual(b'\x43\x91\x97\xbd\x5b\x50\xac\x25\x87\xc2\xc4\x6b\xc7\xe9\x38\xc0', data[:16]) self.assertEqual(b'\x43\x91\x97\xbd\x5b\x50\xac\x25\x87\xc2\xc4\x6b\xc7\xe9\x38\xc0', data[:16])
def test_2_read (self): def test_2_read(self):
rsock = LoopSocket() rsock = LoopSocket()
wsock = LoopSocket() wsock = LoopSocket()
rsock.link(wsock) rsock.link(wsock)

View File

@ -23,7 +23,8 @@ Some unit tests for public/private key objects.
from binascii import hexlify from binascii import hexlify
import unittest import unittest
from paramiko import RSAKey, DSSKey, ECDSAKey, Message, util from paramiko import RSAKey, DSSKey, ECDSAKey, Message, util
from paramiko.common import rng, StringIO, byte_chr, b, bytes from paramiko.py3compat import StringIO, byte_chr, b, bytes
from paramiko.common import rng
from tests.util import test_path from tests.util import test_path
# from openssh's ssh-keygen # from openssh's ssh-keygen

View File

@ -32,7 +32,8 @@ import unittest
from tempfile import mkstemp from tempfile import mkstemp
import paramiko import paramiko
from paramiko.common import PY2, b, u, StringIO, o777, o600 from paramiko.py3compat import PY2, b, u, StringIO
from paramiko.common import o777, o600, o666, o644
from tests.stub_sftp import StubServer, StubSFTPServer from tests.stub_sftp import StubServer, StubSFTPServer
from tests.loop import LoopSocket from tests.loop import LoopSocket
from tests.util import test_path from tests.util import test_path
@ -554,6 +555,7 @@ class SFTPTest (unittest.TestCase):
with open(localname, 'wb') as f: with open(localname, 'wb') as f:
f.write(text) f.write(text)
saved_progress = [] saved_progress = []
def progress_callback(x, y): def progress_callback(x, y):
saved_progress.append((x, y)) saved_progress.append((x, y))
sftp.put(localname, FOLDER + '/bunny.txt', progress_callback) sftp.put(localname, FOLDER + '/bunny.txt', progress_callback)
@ -663,6 +665,7 @@ class SFTPTest (unittest.TestCase):
with open(localname, 'w') as f: with open(localname, 'w') as f:
f.write(text) f.write(text)
saved_progress = [] saved_progress = []
def progress_callback(x, y): def progress_callback(x, y):
saved_progress.append((x, y)) saved_progress.append((x, y))
res = sftp.put(localname, FOLDER + '/bunny.txt', progress_callback, False) res = sftp.put(localname, FOLDER + '/bunny.txt', progress_callback, False)

View File

@ -23,19 +23,14 @@ a real actual sftp server is contacted, and a new folder is created there to
do test file operations in (so no existing files will be harmed). do test file operations in (so no existing files will be harmed).
""" """
import logging
import os import os
import random import random
import struct import struct
import sys import sys
import threading
import time import time
import unittest import unittest
import paramiko
from paramiko.common import o660 from paramiko.common import o660
from tests.stub_sftp import StubServer, StubSFTPServer
from tests.loop import LoopSocket
from tests.test_sftp import get_sftp from tests.test_sftp import get_sftp
FOLDER = os.environ.get('TEST_FOLDER', 'temp-testing000') FOLDER = os.environ.get('TEST_FOLDER', 'temp-testing000')

View File

@ -23,17 +23,16 @@ Some unit tests for the ssh2 protocol in Transport.
from binascii import hexlify from binascii import hexlify
import select import select
import socket import socket
import sys
import time import time
import threading import threading
import unittest
import random import random
from paramiko import Transport, SecurityOptions, ServerInterface, RSAKey, DSSKey, \ from paramiko import Transport, SecurityOptions, ServerInterface, RSAKey, DSSKey, \
SSHException, BadAuthenticationType, InteractiveQuery, ChannelException SSHException, ChannelException
from paramiko import AUTH_FAILED, AUTH_PARTIALLY_SUCCESSFUL, AUTH_SUCCESSFUL from paramiko import AUTH_FAILED, AUTH_SUCCESSFUL
from paramiko import OPEN_SUCCEEDED, OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED from paramiko import OPEN_SUCCEEDED, OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED
from paramiko.common import MSG_KEXINIT, MSG_CHANNEL_WINDOW_ADJUST, b, bytes from paramiko.common import MSG_KEXINIT, cMSG_CHANNEL_WINDOW_ADJUST
from paramiko.py3compat import bytes
from paramiko.message import Message from paramiko.message import Message
from tests.loop import LoopSocket from tests.loop import LoopSocket
from tests.util import ParamikoTest, test_path from tests.util import ParamikoTest, test_path

View File

@ -23,11 +23,10 @@ Some unit tests for utility functions.
from binascii import hexlify from binascii import hexlify
import errno import errno
import os import os
import unittest
from Crypto.Hash import SHA from Crypto.Hash import SHA
import paramiko.util import paramiko.util
from paramiko.util import lookup_ssh_host_config as host_config from paramiko.util import lookup_ssh_host_config as host_config
from paramiko.py3compat import StringIO, byte_ord, b from paramiko.py3compat import StringIO, byte_ord
from tests.util import ParamikoTest from tests.util import ParamikoTest
@ -338,4 +337,4 @@ AddressFamily inet
IdentityFile something_%l_using_fqdn IdentityFile something_%l_using_fqdn
""" """
config = paramiko.util.parse_ssh_config(StringIO(test_config)) config = paramiko.util.parse_ssh_config(StringIO(test_config))
assert config.lookup('meh') # will die during lookup() if bug regresses assert config.lookup('meh') # will die during lookup() if bug regresses