summaryrefslogtreecommitdiffhomepage
path: root/paramiko/transport.py
diff options
context:
space:
mode:
Diffstat (limited to 'paramiko/transport.py')
-rw-r--r--paramiko/transport.py355
1 files changed, 185 insertions, 170 deletions
diff --git a/paramiko/transport.py b/paramiko/transport.py
index ad245a69..1471b543 100644
--- a/paramiko/transport.py
+++ b/paramiko/transport.py
@@ -20,10 +20,7 @@
Core protocol implementation
"""
-import os
import socket
-import string
-import struct
import sys
import threading
import time
@@ -33,7 +30,17 @@ import paramiko
from paramiko import util
from paramiko.auth_handler import AuthHandler
from paramiko.channel import Channel
-from paramiko.common import *
+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.dsskey import DSSKey
from paramiko.kex_gex import KexGex
@@ -41,12 +48,13 @@ from paramiko.kex_group1 import KexGroup1
from paramiko.message import Message
from paramiko.packet import Packetizer, NeedRekeyException
from paramiko.primes import ModulusPack
+from paramiko.py3compat import string_types, long, byte_ord, b
from paramiko.rsakey import RSAKey
from paramiko.ecdsakey import ECDSAKey
from paramiko.server import ServerInterface
from paramiko.sftp_client import SFTPClient
from paramiko.ssh_exception import (SSHException, BadAuthenticationType,
- ChannelException, ProxyCommandFailure)
+ ChannelException, ProxyCommandFailure)
from paramiko.util import retry_on_signal
from Crypto import Random
@@ -60,9 +68,11 @@ except ImportError:
# for thread cleanup
_active_threads = []
+
def _join_lingering_threads():
for thr in _active_threads:
thr.stop_thread()
+
import atexit
atexit.register(_join_lingering_threads)
@@ -76,54 +86,53 @@ class Transport (threading.Thread):
forwardings).
"""
_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',
- 'arcfour128', 'arcfour256' )
- _preferred_macs = ( 'hmac-sha1', 'hmac-md5', 'hmac-sha1-96', 'hmac-md5-96' )
- _preferred_keys = ( 'ssh-rsa', 'ssh-dss', 'ecdsa-sha2-nistp256' )
- _preferred_kex = ( 'diffie-hellman-group1-sha1', 'diffie-hellman-group-exchange-sha1' )
- _preferred_compression = ( 'none', )
+ _preferred_ciphers = ('aes128-ctr', 'aes256-ctr', 'aes128-cbc', 'blowfish-cbc',
+ 'aes256-cbc', '3des-cbc', 'arcfour128', 'arcfour256')
+ _preferred_macs = ('hmac-sha1', 'hmac-md5', 'hmac-sha1-96', 'hmac-md5-96')
+ _preferred_keys = ('ssh-rsa', 'ssh-dss', 'ecdsa-sha2-nistp256')
+ _preferred_kex = ('diffie-hellman-group1-sha1', 'diffie-hellman-group-exchange-sha1')
+ _preferred_compression = ('none',)
_cipher_info = {
- '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 },
- '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 },
- '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 },
- 'arcfour128': { 'class': ARC4, 'mode': None, 'block-size': 8, 'key-size': 16 },
- 'arcfour256': { 'class': ARC4, 'mode': None, 'block-size': 8, 'key-size': 32 },
- }
+ '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},
+ '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},
+ '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},
+ 'arcfour128': {'class': ARC4, 'mode': None, 'block-size': 8, 'key-size': 16},
+ 'arcfour256': {'class': ARC4, 'mode': None, 'block-size': 8, 'key-size': 32},
+ }
_mac_info = {
- 'hmac-sha1': { 'class': SHA, 'size': 20 },
- 'hmac-sha1-96': { 'class': SHA, 'size': 12 },
- 'hmac-md5': { 'class': MD5, 'size': 16 },
- 'hmac-md5-96': { 'class': MD5, 'size': 12 },
- }
+ 'hmac-sha1': {'class': SHA, 'size': 20},
+ 'hmac-sha1-96': {'class': SHA, 'size': 12},
+ 'hmac-md5': {'class': MD5, 'size': 16},
+ 'hmac-md5-96': {'class': MD5, 'size': 12},
+ }
_key_info = {
'ssh-rsa': RSAKey,
'ssh-dss': DSSKey,
'ecdsa-sha2-nistp256': ECDSAKey,
- }
+ }
_kex_info = {
'diffie-hellman-group1-sha1': KexGroup1,
'diffie-hellman-group-exchange-sha1': KexGex,
- }
+ }
_compression_info = {
# zlib@openssh.com is just zlib, but only turned on after a successful
# authentication. openssh servers may only offer this type because
# they've had troubles with security holes in zlib in the past.
- 'zlib@openssh.com': ( ZlibCompressor, ZlibDecompressor ),
- 'zlib': ( ZlibCompressor, ZlibDecompressor ),
- 'none': ( None, None ),
+ 'zlib@openssh.com': (ZlibCompressor, ZlibDecompressor),
+ 'zlib': (ZlibCompressor, ZlibDecompressor),
+ 'none': (None, None),
}
-
_modulus_pack = None
def __init__(self, sock):
@@ -155,7 +164,7 @@ class Transport (threading.Thread):
:param socket sock:
a socket or socket-like object to create the session over.
"""
- if isinstance(sock, (str, unicode)):
+ if isinstance(sock, string_types):
# convert "host:port" into (host, port)
hl = sock.split(':', 1)
if len(hl) == 1:
@@ -173,7 +182,7 @@ class Transport (threading.Thread):
sock = socket.socket(af, socket.SOCK_STREAM)
try:
retry_on_signal(lambda: sock.connect((hostname, port)))
- except socket.error, e:
+ except socket.error as e:
reason = str(e)
else:
break
@@ -220,8 +229,8 @@ class Transport (threading.Thread):
# tracking open channels
self._channels = ChannelMap()
- self.channel_events = { } # (id -> Event)
- self.channels_seen = { } # (id -> True)
+ self.channel_events = {} # (id -> Event)
+ self.channels_seen = {} # (id -> True)
self._channel_counter = 1
self.window_size = 65536
self.max_packet_size = 34816
@@ -244,16 +253,16 @@ class Transport (threading.Thread):
# server mode:
self.server_mode = False
self.server_object = None
- self.server_key_dict = { }
- self.server_accepts = [ ]
+ self.server_key_dict = {}
+ self.server_accepts = []
self.server_accept_cv = threading.Condition(self.lock)
- self.subsystem_table = { }
+ self.subsystem_table = {}
def __repr__(self):
"""
Returns a string representation of this object, for debugging.
"""
- out = '<paramiko.Transport at %s' % hex(long(id(self)) & 0xffffffffL)
+ out = '<paramiko.Transport at %s' % hex(long(id(self)) & xffffffff)
if not self.active:
out += ' (unconnected)'
else:
@@ -468,7 +477,7 @@ class Transport (threading.Thread):
"""
Transport._modulus_pack = ModulusPack(rng)
# 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:
file_list.insert(0, filename)
for fn in file_list:
@@ -489,7 +498,7 @@ class Transport (threading.Thread):
if not self.active:
return
self.stop_thread()
- for chan in self._channels.values():
+ for chan in list(self._channels.values()):
chan._unlink()
self.sock.close()
@@ -562,18 +571,16 @@ class Transport (threading.Thread):
"""
return self.open_channel('auth-agent@openssh.com')
- def open_forwarded_tcpip_channel(self, (src_addr, src_port), (dest_addr, dest_port)):
+ def open_forwarded_tcpip_channel(self, src_addr, dest_addr):
"""
Request a new channel back to the client, of type ``"forwarded-tcpip"``.
This is used after a client has requested port forwarding, for sending
incoming connections back to the client.
:param src_addr: originator's address
- :param src_port: originator's port
:param dest_addr: local (server) connected address
- :param dest_port: local (server) connected port
"""
- return self.open_channel('forwarded-tcpip', (dest_addr, dest_port), (src_addr, src_port))
+ return self.open_channel('forwarded-tcpip', dest_addr, src_addr)
def open_channel(self, kind, dest_addr=None, src_addr=None):
"""
@@ -602,7 +609,7 @@ class Transport (threading.Thread):
try:
chanid = self._next_channel()
m = Message()
- m.add_byte(chr(MSG_CHANNEL_OPEN))
+ m.add_byte(cMSG_CHANNEL_OPEN)
m.add_string(kind)
m.add_int(chanid)
m.add_int(self.window_size)
@@ -625,7 +632,7 @@ class Transport (threading.Thread):
self.lock.release()
self._send_user_message(m)
while True:
- event.wait(0.1);
+ event.wait(0.1)
if not self.active:
e = self.get_exception()
if e is None:
@@ -670,7 +677,6 @@ class Transport (threading.Thread):
"""
if not self.active:
raise SSHException('SSH session not active')
- address = str(address)
port = int(port)
response = self.global_request('tcpip-forward', (address, port), wait=True)
if response is None:
@@ -678,7 +684,9 @@ class Transport (threading.Thread):
if port == 0:
port = response.get_int()
if handler is None:
- def default_handler(channel, (src_addr, src_port), (dest_addr, dest_port)):
+ def default_handler(channel, src_addr, dest_addr_port):
+ #src_addr, src_port = src_addr_port
+ #dest_addr, dest_port = dest_addr_port
self._queue_incoming_channel(channel)
handler = default_handler
self._tcp_handler = handler
@@ -710,22 +718,22 @@ class Transport (threading.Thread):
"""
return SFTPClient.from_transport(self)
- def send_ignore(self, bytes=None):
+ def send_ignore(self, byte_count=None):
"""
Send a junk packet across the encrypted link. This is sometimes used
to add "noise" to a connection to confuse would-be attackers. It can
also be used as a keep-alive for long lived connections traversing
firewalls.
- :param int bytes:
+ :param int byte_count:
the number of random bytes to send in the payload of the ignored
packet -- defaults to a random number from 10 to 41.
"""
m = Message()
- m.add_byte(chr(MSG_IGNORE))
- if bytes is None:
- bytes = (ord(rng.read(1)) % 32) + 10
- m.add_bytes(rng.read(bytes))
+ m.add_byte(cMSG_IGNORE)
+ if byte_count is None:
+ byte_count = (byte_ord(rng.read(1)) % 32) + 10
+ m.add_bytes(rng.read(byte_count))
self._send_user_message(m)
def renegotiate_keys(self):
@@ -765,7 +773,7 @@ class Transport (threading.Thread):
0 to disable keepalives).
"""
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):
"""
@@ -787,7 +795,7 @@ class Transport (threading.Thread):
if wait:
self.completion_event = threading.Event()
m = Message()
- m.add_byte(chr(MSG_GLOBAL_REQUEST))
+ m.add_byte(cMSG_GLOBAL_REQUEST)
m.add_string(kind)
m.add_boolean(wait)
if data is not None:
@@ -864,17 +872,17 @@ class Transport (threading.Thread):
supplied by the server is incorrect, or authentication fails.
"""
if hostkey is not None:
- self._preferred_keys = [ hostkey.get_name() ]
+ self._preferred_keys = [hostkey.get_name()]
self.start_client()
# check host key if we were given one
- if (hostkey is not None):
+ if hostkey is not None:
key = self.get_remote_server_key()
- if (key.get_name() != hostkey.get_name()) or (str(key) != str(hostkey)):
+ if (key.get_name() != hostkey.get_name()) or (key.asbytes() != hostkey.asbytes()):
self._log(DEBUG, 'Bad host key from server')
- self._log(DEBUG, 'Expected: %s: %s' % (hostkey.get_name(), repr(str(hostkey))))
- self._log(DEBUG, 'Got : %s: %s' % (key.get_name(), repr(str(key))))
+ self._log(DEBUG, 'Expected: %s: %s' % (hostkey.get_name(), repr(hostkey.asbytes())))
+ self._log(DEBUG, 'Got : %s: %s' % (key.get_name(), repr(key.asbytes())))
raise SSHException('Bad host key from server')
self._log(DEBUG, 'Host key verified (%s)' % hostkey.get_name())
@@ -951,6 +959,18 @@ class Transport (threading.Thread):
return None
return self.auth_handler.get_username()
+ def get_banner(self):
+ """
+ Return the banner supplied by the server upon connect. If no banner is
+ supplied, this method returns C{None}.
+
+ @return: server supplied banner, or C{None}.
+ @rtype: string
+ """
+ if not self.active or (self.auth_handler is None):
+ return None
+ return self.auth_handler.banner
+
def auth_none(self, username):
"""
Try to authenticate to the server using no authentication at all.
@@ -1036,9 +1056,9 @@ class Transport (threading.Thread):
return []
try:
return self.auth_handler.wait_for_response(my_event)
- except BadAuthenticationType, x:
+ except BadAuthenticationType as e:
# if password auth isn't allowed, but keyboard-interactive *is*, try to fudge it
- if not fallback or ('keyboard-interactive' not in x.allowed_types):
+ if not fallback or ('keyboard-interactive' not in e.allowed_types):
raise
try:
def handler(title, instructions, fields):
@@ -1050,12 +1070,11 @@ class Transport (threading.Thread):
# to try to fake out automated scripting of the exact
# type we're doing here. *shrug* :)
return []
- return [ password ]
+ return [password]
return self.auth_interactive(username, handler)
- except SSHException, ignored:
+ except SSHException:
# attempt failed; just raise the original exception
- raise x
- return None
+ raise e
def auth_publickey(self, username, key, event=None):
"""
@@ -1216,9 +1235,9 @@ class Transport (threading.Thread):
.. versionadded:: 1.5.2
"""
if compress:
- self._preferred_compression = ( 'zlib@openssh.com', 'zlib', 'none' )
+ self._preferred_compression = ('zlib@openssh.com', 'zlib', 'none')
else:
- self._preferred_compression = ( 'none', )
+ self._preferred_compression = ('none',)
def getpeername(self):
"""
@@ -1233,7 +1252,7 @@ class Transport (threading.Thread):
"""
gp = getattr(self.sock, 'getpeername', None)
if gp is None:
- return ('unknown', 0)
+ return 'unknown', 0
return gp()
def stop_thread(self):
@@ -1242,10 +1261,8 @@ class Transport (threading.Thread):
while self.isAlive():
self.join(10)
-
### internals...
-
def _log(self, level, msg, *args):
if issubclass(type(msg), list):
for m in msg:
@@ -1254,11 +1271,11 @@ class Transport (threading.Thread):
self.logger.log(level, msg, *args)
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
def _next_channel(self):
- "you are holding the lock"
+ """you are holding the lock"""
chanid = self._channel_counter
while self._channels.get(chanid) is not None:
self._channel_counter = (self._channel_counter + 1) & 0xffffff
@@ -1267,7 +1284,7 @@ class Transport (threading.Thread):
return 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)
def _send_message(self, data):
@@ -1296,14 +1313,14 @@ class Transport (threading.Thread):
self.clear_to_send_lock.release()
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.H = h
- if self.session_id == None:
+ if self.session_id is None:
self.session_id = h
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)
def _verify_key(self, host_key, sig):
@@ -1315,19 +1332,19 @@ class Transport (threading.Thread):
self.host_key = key
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.add_mpint(self.K)
m.add_bytes(self.H)
- m.add_byte(id)
+ m.add_byte(b(id))
m.add_bytes(self.session_id)
- out = sofar = SHA.new(str(m)).digest()
+ out = sofar = SHA.new(m.asbytes()).digest()
while len(out) < nbytes:
m = Message()
m.add_mpint(self.K)
m.add_bytes(self.H)
m.add_bytes(sofar)
- digest = SHA.new(str(m)).digest()
+ digest = SHA.new(m.asbytes()).digest()
out += digest
sofar += digest
return out[:nbytes]
@@ -1361,7 +1378,7 @@ class Transport (threading.Thread):
# only called if a channel has turned on x11 forwarding
if handler is None:
# by default, use the same mechanism as accept()
- def default_handler(channel, (src_addr, src_port)):
+ def default_handler(channel, src_addr_port):
self._queue_incoming_channel(channel)
self._x11_handler = default_handler
else:
@@ -1392,12 +1409,12 @@ class Transport (threading.Thread):
# active=True occurs before the thread is launched, to avoid a race
_active_threads.append(self)
if self.server_mode:
- self._log(DEBUG, 'starting thread (server mode): %s' % hex(long(id(self)) & 0xffffffffL))
+ self._log(DEBUG, 'starting thread (server mode): %s' % hex(long(id(self)) & xffffffff))
else:
- self._log(DEBUG, 'starting thread (client mode): %s' % hex(long(id(self)) & 0xffffffffL))
+ self._log(DEBUG, 'starting thread (client mode): %s' % hex(long(id(self)) & xffffffff))
try:
try:
- self.packetizer.write_all(self.local_version + '\r\n')
+ self.packetizer.write_all(b(self.local_version + '\r\n'))
self._check_banner()
self._send_kex_init()
self._expect_packet(MSG_KEXINIT)
@@ -1445,38 +1462,38 @@ class Transport (threading.Thread):
else:
self._log(WARNING, 'Oops, unhandled type %d' % ptype)
msg = Message()
- msg.add_byte(chr(MSG_UNIMPLEMENTED))
+ msg.add_byte(cMSG_UNIMPLEMENTED)
msg.add_int(m.seqno)
self._send_message(msg)
- except SSHException, e:
+ except SSHException as e:
self._log(ERROR, 'Exception: ' + str(e))
self._log(ERROR, util.tb_strings())
self.saved_exception = e
- except EOFError, e:
+ except EOFError as e:
self._log(DEBUG, 'EOF in transport thread')
#self._log(DEBUG, util.tb_strings())
self.saved_exception = e
- except socket.error, e:
+ except socket.error as e:
if type(e.args) is tuple:
if e.args:
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)
else:
emsg = e.args
self._log(ERROR, 'Socket exception: ' + emsg)
self.saved_exception = e
- except Exception, e:
+ except Exception as e:
self._log(ERROR, 'Unknown exception: ' + str(e))
self._log(ERROR, util.tb_strings())
self.saved_exception = e
_active_threads.remove(self)
- for chan in self._channels.values():
+ for chan in list(self._channels.values()):
chan._unlink()
if self.active:
self.active = False
self.packetizer.close()
- if self.completion_event != None:
+ if self.completion_event is not None:
self.completion_event.set()
if self.auth_handler is not None:
self.auth_handler.abort()
@@ -1496,10 +1513,8 @@ class Transport (threading.Thread):
if self.sys.modules is not None:
raise
-
### protocol stages
-
def _negotiate_keys(self, m):
# throws SSHException on anything unusual
self.clear_to_send_lock.acquire()
@@ -1507,7 +1522,7 @@ class Transport (threading.Thread):
self.clear_to_send.clear()
finally:
self.clear_to_send_lock.release()
- if self.local_kex_init == None:
+ if self.local_kex_init is None:
# remote side wants to renegotiate
self._send_kex_init()
self._parse_kex_init(m)
@@ -1526,8 +1541,8 @@ class Transport (threading.Thread):
buf = self.packetizer.readline(timeout)
except ProxyCommandFailure:
raise
- except Exception, x:
- raise SSHException('Error reading SSH protocol banner' + str(x))
+ except Exception as e:
+ raise SSHException('Error reading SSH protocol banner' + str(e))
if buf[:4] == 'SSH-':
break
self._log(DEBUG, 'Banner: ' + buf)
@@ -1537,7 +1552,7 @@ class Transport (threading.Thread):
self.remote_version = buf
# pull off any attached comment
comment = ''
- i = string.find(buf, ' ')
+ i = buf.find(' ')
if i >= 0:
comment = buf[i+1:]
buf = buf[:i]
@@ -1568,13 +1583,13 @@ class Transport (threading.Thread):
pkex = list(self.get_security_options().kex)
pkex.remove('diffie-hellman-group-exchange-sha1')
self.get_security_options().kex = pkex
- available_server_keys = filter(self.server_key_dict.keys().__contains__,
- self._preferred_keys)
+ available_server_keys = list(filter(list(self.server_key_dict.keys()).__contains__,
+ self._preferred_keys))
else:
available_server_keys = self._preferred_keys
m = Message()
- m.add_byte(chr(MSG_KEXINIT))
+ m.add_byte(cMSG_KEXINIT)
m.add_bytes(rng.read(16))
m.add_list(self._preferred_kex)
m.add_list(available_server_keys)
@@ -1584,12 +1599,12 @@ class Transport (threading.Thread):
m.add_list(self._preferred_macs)
m.add_list(self._preferred_compression)
m.add_list(self._preferred_compression)
- m.add_string('')
- m.add_string('')
+ m.add_string(bytes())
+ m.add_string(bytes())
m.add_boolean(False)
m.add_int(0)
# save a copy for later (needed to compute a hash)
- self.local_kex_init = str(m)
+ self.local_kex_init = m.asbytes()
self._send_message(m)
def _parse_kex_init(self, m):
@@ -1607,33 +1622,33 @@ class Transport (threading.Thread):
kex_follows = m.get_boolean()
unused = m.get_int()
- self._log(DEBUG, 'kex algos:' + str(kex_algo_list) + ' server key:' + str(server_key_algo_list) + \
- ' client encrypt:' + str(client_encrypt_algo_list) + \
- ' server encrypt:' + str(server_encrypt_algo_list) + \
- ' client mac:' + str(client_mac_algo_list) + \
- ' server mac:' + str(server_mac_algo_list) + \
- ' client compress:' + str(client_compress_algo_list) + \
- ' server compress:' + str(server_compress_algo_list) + \
- ' client lang:' + str(client_lang_list) + \
- ' server lang:' + str(server_lang_list) + \
+ self._log(DEBUG, 'kex algos:' + str(kex_algo_list) + ' server key:' + str(server_key_algo_list) +
+ ' client encrypt:' + str(client_encrypt_algo_list) +
+ ' server encrypt:' + str(server_encrypt_algo_list) +
+ ' client mac:' + str(client_mac_algo_list) +
+ ' server mac:' + str(server_mac_algo_list) +
+ ' client compress:' + str(client_compress_algo_list) +
+ ' server compress:' + str(server_compress_algo_list) +
+ ' client lang:' + str(client_lang_list) +
+ ' server lang:' + str(server_lang_list) +
' kex follows?' + str(kex_follows))
# as a server, we pick the first item in the client's list that we support.
# as a client, we pick the first item in our list that the server supports.
if self.server_mode:
- agreed_kex = filter(self._preferred_kex.__contains__, kex_algo_list)
+ agreed_kex = list(filter(self._preferred_kex.__contains__, kex_algo_list))
else:
- agreed_kex = filter(kex_algo_list.__contains__, self._preferred_kex)
+ agreed_kex = list(filter(kex_algo_list.__contains__, self._preferred_kex))
if len(agreed_kex) == 0:
raise SSHException('Incompatible ssh peer (no acceptable kex algorithm)')
self.kex_engine = self._kex_info[agreed_kex[0]](self)
if self.server_mode:
- available_server_keys = filter(self.server_key_dict.keys().__contains__,
- self._preferred_keys)
- agreed_keys = filter(available_server_keys.__contains__, server_key_algo_list)
+ available_server_keys = list(filter(list(self.server_key_dict.keys()).__contains__,
+ self._preferred_keys))
+ agreed_keys = list(filter(available_server_keys.__contains__, server_key_algo_list))
else:
- agreed_keys = filter(server_key_algo_list.__contains__, self._preferred_keys)
+ agreed_keys = list(filter(server_key_algo_list.__contains__, self._preferred_keys))
if len(agreed_keys) == 0:
raise SSHException('Incompatible ssh peer (no acceptable host key)')
self.host_key_type = agreed_keys[0]
@@ -1641,15 +1656,15 @@ class Transport (threading.Thread):
raise SSHException('Incompatible ssh peer (can\'t match requested host key type)')
if self.server_mode:
- agreed_local_ciphers = filter(self._preferred_ciphers.__contains__,
- server_encrypt_algo_list)
- agreed_remote_ciphers = filter(self._preferred_ciphers.__contains__,
- client_encrypt_algo_list)
+ agreed_local_ciphers = list(filter(self._preferred_ciphers.__contains__,
+ server_encrypt_algo_list))
+ agreed_remote_ciphers = list(filter(self._preferred_ciphers.__contains__,
+ client_encrypt_algo_list))
else:
- agreed_local_ciphers = filter(client_encrypt_algo_list.__contains__,
- self._preferred_ciphers)
- agreed_remote_ciphers = filter(server_encrypt_algo_list.__contains__,
- self._preferred_ciphers)
+ agreed_local_ciphers = list(filter(client_encrypt_algo_list.__contains__,
+ self._preferred_ciphers))
+ agreed_remote_ciphers = list(filter(server_encrypt_algo_list.__contains__,
+ self._preferred_ciphers))
if (len(agreed_local_ciphers) == 0) or (len(agreed_remote_ciphers) == 0):
raise SSHException('Incompatible ssh server (no acceptable ciphers)')
self.local_cipher = agreed_local_ciphers[0]
@@ -1657,22 +1672,22 @@ class Transport (threading.Thread):
self._log(DEBUG, 'Ciphers agreed: local=%s, remote=%s' % (self.local_cipher, self.remote_cipher))
if self.server_mode:
- agreed_remote_macs = filter(self._preferred_macs.__contains__, client_mac_algo_list)
- agreed_local_macs = filter(self._preferred_macs.__contains__, server_mac_algo_list)
+ agreed_remote_macs = list(filter(self._preferred_macs.__contains__, client_mac_algo_list))
+ agreed_local_macs = list(filter(self._preferred_macs.__contains__, server_mac_algo_list))
else:
- agreed_local_macs = filter(client_mac_algo_list.__contains__, self._preferred_macs)
- agreed_remote_macs = filter(server_mac_algo_list.__contains__, self._preferred_macs)
+ agreed_local_macs = list(filter(client_mac_algo_list.__contains__, self._preferred_macs))
+ agreed_remote_macs = list(filter(server_mac_algo_list.__contains__, self._preferred_macs))
if (len(agreed_local_macs) == 0) or (len(agreed_remote_macs) == 0):
raise SSHException('Incompatible ssh server (no acceptable macs)')
self.local_mac = agreed_local_macs[0]
self.remote_mac = agreed_remote_macs[0]
if self.server_mode:
- agreed_remote_compression = filter(self._preferred_compression.__contains__, client_compress_algo_list)
- agreed_local_compression = filter(self._preferred_compression.__contains__, server_compress_algo_list)
+ agreed_remote_compression = list(filter(self._preferred_compression.__contains__, client_compress_algo_list))
+ agreed_local_compression = list(filter(self._preferred_compression.__contains__, server_compress_algo_list))
else:
- agreed_local_compression = filter(client_compress_algo_list.__contains__, self._preferred_compression)
- agreed_remote_compression = filter(server_compress_algo_list.__contains__, self._preferred_compression)
+ agreed_local_compression = list(filter(client_compress_algo_list.__contains__, self._preferred_compression))
+ agreed_remote_compression = list(filter(server_compress_algo_list.__contains__, self._preferred_compression))
if (len(agreed_local_compression) == 0) or (len(agreed_remote_compression) == 0):
raise SSHException('Incompatible ssh server (no acceptable compression) %r %r %r' % (agreed_local_compression, agreed_remote_compression, self._preferred_compression))
self.local_compression = agreed_local_compression[0]
@@ -1687,10 +1702,10 @@ class Transport (threading.Thread):
# actually some extra bytes (one NUL byte in openssh's case) added to
# the end of the packet but not parsed. turns out we need to throw
# away those bytes because they aren't part of the hash.
- self.remote_kex_init = chr(MSG_KEXINIT) + m.get_so_far()
+ self.remote_kex_init = cMSG_KEXINIT + m.get_so_far()
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']
if self.server_mode:
IV_in = self._compute_key('A', block_size)
@@ -1714,9 +1729,9 @@ class Transport (threading.Thread):
self.packetizer.set_inbound_compressor(compress_in())
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.add_byte(chr(MSG_NEWKEYS))
+ m.add_byte(cMSG_NEWKEYS)
self._send_message(m)
block_size = self._cipher_info[self.local_cipher]['block-size']
if self.server_mode:
@@ -1771,7 +1786,7 @@ class Transport (threading.Thread):
# this was the first key exchange
self.initial_kex_done = True
# send an event?
- if self.completion_event != None:
+ if self.completion_event is not None:
self.completion_event.set()
# it's now okay to send data again (if this was a re-key)
if not self.packetizer.need_rekey():
@@ -1785,24 +1800,24 @@ class Transport (threading.Thread):
def _parse_disconnect(self, m):
code = m.get_int()
- desc = m.get_string()
+ desc = m.get_text()
self._log(INFO, 'Disconnect (code %d): %s' % (code, desc))
def _parse_global_request(self, m):
- kind = m.get_string()
+ kind = m.get_text()
self._log(DEBUG, 'Received global request "%s"' % kind)
want_reply = m.get_boolean()
if not self.server_mode:
self._log(DEBUG, 'Rejecting "%s" global request from server.' % kind)
ok = False
elif kind == 'tcpip-forward':
- address = m.get_string()
+ address = m.get_text()
port = m.get_int()
ok = self.server_object.check_port_forward_request(address, port)
- if ok != False:
+ if ok:
ok = (ok,)
elif kind == 'cancel-tcpip-forward':
- address = m.get_string()
+ address = m.get_text()
port = m.get_int()
self.server_object.cancel_port_forward_request(address, port)
ok = True
@@ -1815,10 +1830,10 @@ class Transport (threading.Thread):
if want_reply:
msg = Message()
if ok:
- msg.add_byte(chr(MSG_REQUEST_SUCCESS))
+ msg.add_byte(cMSG_REQUEST_SUCCESS)
msg.add(*extra)
else:
- msg.add_byte(chr(MSG_REQUEST_FAILURE))
+ msg.add_byte(cMSG_REQUEST_FAILURE)
self._send_message(msg)
def _parse_request_success(self, m):
@@ -1856,8 +1871,8 @@ class Transport (threading.Thread):
def _parse_channel_open_failure(self, m):
chanid = m.get_int()
reason = m.get_int()
- reason_str = m.get_string()
- lang = m.get_string()
+ reason_str = m.get_text()
+ lang = m.get_text()
reason_text = CONNECTION_FAILED_CODE.get(reason, '(unknown code)')
self._log(INFO, 'Secsh channel %d open FAILED: %s: %s' % (chanid, reason_str, reason_text))
self.lock.acquire()
@@ -1873,7 +1888,7 @@ class Transport (threading.Thread):
return
def _parse_channel_open(self, m):
- kind = m.get_string()
+ kind = m.get_text()
chanid = m.get_int()
initial_window_size = m.get_int()
max_packet_size = m.get_int()
@@ -1886,7 +1901,7 @@ class Transport (threading.Thread):
finally:
self.lock.release()
elif (kind == 'x11') and (self._x11_handler is not None):
- origin_addr = m.get_string()
+ origin_addr = m.get_text()
origin_port = m.get_int()
self._log(DEBUG, 'Incoming x11 connection from %s:%d' % (origin_addr, origin_port))
self.lock.acquire()
@@ -1895,9 +1910,9 @@ class Transport (threading.Thread):
finally:
self.lock.release()
elif (kind == 'forwarded-tcpip') and (self._tcp_handler is not None):
- server_addr = m.get_string()
+ server_addr = m.get_text()
server_port = m.get_int()
- origin_addr = m.get_string()
+ origin_addr = m.get_text()
origin_port = m.get_int()
self._log(DEBUG, 'Incoming tcp forwarded connection from %s:%d' % (origin_addr, origin_port))
self.lock.acquire()
@@ -1917,13 +1932,12 @@ class Transport (threading.Thread):
self.lock.release()
if kind == 'direct-tcpip':
# handle direct-tcpip requests comming from the client
- dest_addr = m.get_string()
+ dest_addr = m.get_text()
dest_port = m.get_int()
- origin_addr = m.get_string()
+ origin_addr = m.get_text()
origin_port = m.get_int()
reason = self.server_object.check_channel_direct_tcpip_request(
- my_chanid, (origin_addr, origin_port),
- (dest_addr, dest_port))
+ my_chanid, (origin_addr, origin_port), (dest_addr, dest_port))
else:
reason = self.server_object.check_channel_request(kind, my_chanid)
if reason != OPEN_SUCCEEDED:
@@ -1931,7 +1945,7 @@ class Transport (threading.Thread):
reject = True
if reject:
msg = Message()
- msg.add_byte(chr(MSG_CHANNEL_OPEN_FAILURE))
+ msg.add_byte(cMSG_CHANNEL_OPEN_FAILURE)
msg.add_int(chanid)
msg.add_int(reason)
msg.add_string('')
@@ -1950,7 +1964,7 @@ class Transport (threading.Thread):
finally:
self.lock.release()
m = Message()
- m.add_byte(chr(MSG_CHANNEL_OPEN_SUCCESS))
+ m.add_byte(cMSG_CHANNEL_OPEN_SUCCESS)
m.add_int(chanid)
m.add_int(my_chanid)
m.add_int(self.window_size)
@@ -1977,7 +1991,7 @@ class Transport (threading.Thread):
try:
self.lock.acquire()
if name not in self.subsystem_table:
- return (None, [], {})
+ return None, [], {}
return self.subsystem_table[name]
finally:
self.lock.release()
@@ -1991,7 +2005,7 @@ class Transport (threading.Thread):
MSG_CHANNEL_OPEN_FAILURE: _parse_channel_open_failure,
MSG_CHANNEL_OPEN: _parse_channel_open,
MSG_KEXINIT: _negotiate_keys,
- }
+ }
_channel_handler_table = {
MSG_CHANNEL_SUCCESS: Channel._request_success,
@@ -2002,7 +2016,7 @@ class Transport (threading.Thread):
MSG_CHANNEL_REQUEST: Channel._handle_request,
MSG_CHANNEL_EOF: Channel._handle_eof,
MSG_CHANNEL_CLOSE: Channel._handle_close,
- }
+ }
class SecurityOptions (object):
@@ -2017,7 +2031,8 @@ class SecurityOptions (object):
``ValueError`` will be raised. If you try to assign something besides a
tuple to one of the fields, ``TypeError`` will be raised.
"""
- __slots__ = [ 'ciphers', 'digests', 'key_types', 'kex', 'compression', '_transport' ]
+ #__slots__ = [ 'ciphers', 'digests', 'key_types', 'kex', 'compression', '_transport' ]
+ __slots__ = '_transport'
def __init__(self, transport):
self._transport = transport
@@ -2048,8 +2063,8 @@ class SecurityOptions (object):
x = tuple(x)
if type(x) is not tuple:
raise TypeError('expected tuple or list')
- possible = getattr(self._transport, orig).keys()
- forbidden = filter(lambda n: n not in possible, x)
+ possible = list(getattr(self._transport, orig).keys())
+ forbidden = [n for n in x if n not in possible]
if len(forbidden) > 0:
raise ValueError('unknown cipher')
setattr(self._transport, name, x)
@@ -2113,7 +2128,7 @@ class ChannelMap (object):
def values(self):
self._lock.acquire()
try:
- return self._map.values()
+ return list(self._map.values())
finally:
self._lock.release()