summaryrefslogtreecommitdiffhomepage
path: root/paramiko/transport.py
diff options
context:
space:
mode:
Diffstat (limited to 'paramiko/transport.py')
-rw-r--r--paramiko/transport.py956
1 files changed, 534 insertions, 422 deletions
diff --git a/paramiko/transport.py b/paramiko/transport.py
index 7fe34d40..a0890805 100644
--- a/paramiko/transport.py
+++ b/paramiko/transport.py
@@ -39,18 +39,49 @@ from paramiko.auth_handler import AuthHandler
from paramiko.ssh_gss import GSSAuth
from paramiko.channel import Channel
from paramiko.common import (
- 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, MIN_WINDOW_SIZE, MIN_PACKET_SIZE, MAX_WINDOW_SIZE,
- DEFAULT_WINDOW_SIZE, DEFAULT_MAX_PACKET_SIZE, HIGHEST_USERAUTH_MESSAGE_ID,
+ 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,
+ MIN_WINDOW_SIZE,
+ MIN_PACKET_SIZE,
+ MAX_WINDOW_SIZE,
+ DEFAULT_WINDOW_SIZE,
+ DEFAULT_MAX_PACKET_SIZE,
+ HIGHEST_USERAUTH_MESSAGE_ID,
)
from paramiko.compress import ZlibCompressor, ZlibDecompressor
from paramiko.dsskey import DSSKey
@@ -69,7 +100,10 @@ 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,
+ SSHException,
+ BadAuthenticationType,
+ ChannelException,
+ ProxyCommandFailure,
)
from paramiko.util import retry_on_signal, ClosingContextManager, clamp_value
@@ -77,12 +111,14 @@ from paramiko.util import retry_on_signal, ClosingContextManager, clamp_value
# for thread cleanup
_active_threads = []
+
def _join_lingering_threads():
for thr in _active_threads:
thr.stop_thread()
import atexit
+
atexit.register(_join_lingering_threads)
@@ -96,31 +132,32 @@ class Transport(threading.Thread, ClosingContextManager):
Instances of this class may be used as context managers.
"""
+
_ENCRYPT = object()
_DECRYPT = object()
- _PROTO_ID = '2.0'
- _CLIENT_ID = 'paramiko_%s' % paramiko.__version__
+ _PROTO_ID = "2.0"
+ _CLIENT_ID = "paramiko_%s" % paramiko.__version__
# These tuples of algorithm identifiers are in preference order; do not
# reorder without reason!
_preferred_ciphers = (
- 'aes128-ctr',
- 'aes192-ctr',
- 'aes256-ctr',
- 'aes128-cbc',
- 'aes192-cbc',
- 'aes256-cbc',
- 'blowfish-cbc',
- '3des-cbc',
+ "aes128-ctr",
+ "aes192-ctr",
+ "aes256-ctr",
+ "aes128-cbc",
+ "aes192-cbc",
+ "aes256-cbc",
+ "blowfish-cbc",
+ "3des-cbc",
)
_preferred_macs = (
- 'hmac-sha2-256',
- 'hmac-sha2-512',
- 'hmac-sha1',
- 'hmac-md5',
- 'hmac-sha1-96',
- 'hmac-md5-96',
+ "hmac-sha2-256",
+ "hmac-sha2-512",
+ "hmac-sha1",
+ "hmac-md5",
+ "hmac-sha1-96",
+ "hmac-md5-96",
)
_preferred_keys = (
'ssh-ed25519',
@@ -140,71 +177,70 @@ class Transport(threading.Thread, ClosingContextManager):
'diffie-hellman-group1-sha1',
)
_preferred_gsskex = (
- 'gss-gex-sha1-toWM5Slw5Ew8Mqkay+al2g==',
- 'gss-group14-sha1-toWM5Slw5Ew8Mqkay+al2g==',
- 'gss-group1-sha1-toWM5Slw5Ew8Mqkay+al2g==',
+ "gss-gex-sha1-toWM5Slw5Ew8Mqkay+al2g==",
+ "gss-group14-sha1-toWM5Slw5Ew8Mqkay+al2g==",
+ "gss-group1-sha1-toWM5Slw5Ew8Mqkay+al2g==",
)
- _preferred_compression = ('none',)
+ _preferred_compression = ("none",)
_cipher_info = {
- 'aes128-ctr': {
- 'class': algorithms.AES,
- 'mode': modes.CTR,
- 'block-size': 16,
- 'key-size': 16
+ "aes128-ctr": {
+ "class": algorithms.AES,
+ "mode": modes.CTR,
+ "block-size": 16,
+ "key-size": 16,
},
- 'aes192-ctr': {
- 'class': algorithms.AES,
- 'mode': modes.CTR,
- 'block-size': 16,
- 'key-size': 24
+ "aes192-ctr": {
+ "class": algorithms.AES,
+ "mode": modes.CTR,
+ "block-size": 16,
+ "key-size": 24,
},
- 'aes256-ctr': {
- 'class': algorithms.AES,
- 'mode': modes.CTR,
- 'block-size': 16,
- 'key-size': 32
+ "aes256-ctr": {
+ "class": algorithms.AES,
+ "mode": modes.CTR,
+ "block-size": 16,
+ "key-size": 32,
},
- 'blowfish-cbc': {
- 'class': algorithms.Blowfish,
- 'mode': modes.CBC,
- 'block-size': 8,
- 'key-size': 16
+ "blowfish-cbc": {
+ "class": algorithms.Blowfish,
+ "mode": modes.CBC,
+ "block-size": 8,
+ "key-size": 16,
},
- 'aes128-cbc': {
- 'class': algorithms.AES,
- 'mode': modes.CBC,
- 'block-size': 16,
- 'key-size': 16
+ "aes128-cbc": {
+ "class": algorithms.AES,
+ "mode": modes.CBC,
+ "block-size": 16,
+ "key-size": 16,
},
- 'aes192-cbc': {
- 'class': algorithms.AES,
- 'mode': modes.CBC,
- 'block-size': 16,
- 'key-size': 24
+ "aes192-cbc": {
+ "class": algorithms.AES,
+ "mode": modes.CBC,
+ "block-size": 16,
+ "key-size": 24,
},
- 'aes256-cbc': {
- 'class': algorithms.AES,
- 'mode': modes.CBC,
- 'block-size': 16,
- 'key-size': 32
+ "aes256-cbc": {
+ "class": algorithms.AES,
+ "mode": modes.CBC,
+ "block-size": 16,
+ "key-size": 32,
},
- '3des-cbc': {
- 'class': algorithms.TripleDES,
- 'mode': modes.CBC,
- 'block-size': 8,
- 'key-size': 24
+ "3des-cbc": {
+ "class": algorithms.TripleDES,
+ "mode": modes.CBC,
+ "block-size": 8,
+ "key-size": 24,
},
}
-
_mac_info = {
- 'hmac-sha1': {'class': sha1, 'size': 20},
- 'hmac-sha1-96': {'class': sha1, 'size': 12},
- 'hmac-sha2-256': {'class': sha256, 'size': 32},
- 'hmac-sha2-512': {'class': sha512, 'size': 64},
- 'hmac-md5': {'class': md5, 'size': 16},
- 'hmac-md5-96': {'class': md5, 'size': 12},
+ "hmac-sha1": {"class": sha1, "size": 20},
+ "hmac-sha1-96": {"class": sha1, "size": 12},
+ "hmac-sha2-256": {"class": sha256, "size": 32},
+ "hmac-sha2-512": {"class": sha512, "size": 64},
+ "hmac-md5": {"class": md5, "size": 16},
+ "hmac-md5-96": {"class": md5, "size": 12},
}
_key_info = {
@@ -233,20 +269,22 @@ class Transport(threading.Thread, ClosingContextManager):
# 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
_active_check_timeout = 0.1
- def __init__(self,
- sock,
- default_window_size=DEFAULT_WINDOW_SIZE,
- default_max_packet_size=DEFAULT_MAX_PACKET_SIZE,
- gss_kex=False,
- gss_deleg_creds=True):
+ def __init__(
+ self,
+ sock,
+ default_window_size=DEFAULT_WINDOW_SIZE,
+ default_max_packet_size=DEFAULT_MAX_PACKET_SIZE,
+ gss_kex=False,
+ gss_deleg_creds=True,
+ ):
"""
Create a new SSH session over an existing socket, or socket-like
object. This only creates the `.Transport` object; it doesn't begin
@@ -295,7 +333,7 @@ class Transport(threading.Thread, ClosingContextManager):
if isinstance(sock, string_types):
# convert "host:port" into (host, port)
- hl = sock.split(':', 1)
+ hl = sock.split(":", 1)
if len(hl) == 1:
sock = (hl[0], 22)
else:
@@ -303,7 +341,7 @@ class Transport(threading.Thread, ClosingContextManager):
if type(sock) is tuple:
# connect to the given (host, port)
hostname, port = sock
- reason = 'No suitable address family'
+ reason = "No suitable address family"
addrinfos = socket.getaddrinfo(
hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM
)
@@ -320,7 +358,8 @@ class Transport(threading.Thread, ClosingContextManager):
break
else:
raise SSHException(
- 'Unable to connect to %s: %s' % (hostname, reason))
+ "Unable to connect to %s: %s" % (hostname, reason)
+ )
# okay, normal socket-ish flow here...
threading.Thread.__init__(self)
self.setDaemon(True)
@@ -331,9 +370,9 @@ class Transport(threading.Thread, ClosingContextManager):
# negotiated crypto parameters
self.packetizer = Packetizer(sock)
- self.local_version = 'SSH-' + self._PROTO_ID + '-' + self._CLIENT_ID
- self.remote_version = ''
- self.local_cipher = self.remote_cipher = ''
+ self.local_version = "SSH-" + self._PROTO_ID + "-" + self._CLIENT_ID
+ self.remote_version = ""
+ self.local_cipher = self.remote_cipher = ""
self.local_kex_init = self.remote_kex_init = None
self.local_mac = self.remote_mac = None
self.local_compression = self.remote_compression = None
@@ -365,8 +404,8 @@ class Transport(threading.Thread, ClosingContextManager):
# 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 = 0
self.default_max_packet_size = default_max_packet_size
self.default_window_size = default_window_size
@@ -378,7 +417,7 @@ class Transport(threading.Thread, ClosingContextManager):
self.clear_to_send = threading.Event()
self.clear_to_send_lock = threading.Lock()
self.clear_to_send_timeout = 30.0
- self.log_name = 'paramiko.transport'
+ self.log_name = "paramiko.transport"
self.logger = util.get_logger(self.log_name)
self.packetizer.set_log(self.logger)
self.auth_handler = None
@@ -406,22 +445,22 @@ class Transport(threading.Thread, ClosingContextManager):
"""
Returns a string representation of this object, for debugging.
"""
- out = '<paramiko.Transport at %s' % hex(long(id(self)) & xffffffff)
+ out = "<paramiko.Transport at %s" % hex(long(id(self)) & xffffffff)
if not self.active:
- out += ' (unconnected)'
+ out += " (unconnected)"
else:
- if self.local_cipher != '':
- out += ' (cipher %s, %d bits)' % (
+ if self.local_cipher != "":
+ out += " (cipher %s, %d bits)" % (
self.local_cipher,
- self._cipher_info[self.local_cipher]['key-size'] * 8
+ self._cipher_info[self.local_cipher]["key-size"] * 8,
)
if self.is_authenticated():
- out += ' (active; %d open channel(s))' % len(self._channels)
+ out += " (active; %d open channel(s))" % len(self._channels)
elif self.initial_kex_done:
- out += ' (connected; awaiting auth)'
+ out += " (connected; awaiting auth)"
else:
- out += ' (connecting)'
- out += '>'
+ out += " (connecting)"
+ out += ">"
return out
def atfork(self):
@@ -508,10 +547,9 @@ class Transport(threading.Thread, ClosingContextManager):
e = self.get_exception()
if e is not None:
raise e
- raise SSHException('Negotiation failed.')
- if (
- event.is_set() or
- (timeout is not None and time.time() >= max_time)
+ raise SSHException("Negotiation failed.")
+ if event.is_set() or (
+ timeout is not None and time.time() >= max_time
):
break
@@ -577,7 +615,7 @@ class Transport(threading.Thread, ClosingContextManager):
e = self.get_exception()
if e is not None:
raise e
- raise SSHException('Negotiation failed.')
+ raise SSHException("Negotiation failed.")
if event.is_set():
break
@@ -644,7 +682,7 @@ class Transport(threading.Thread, ClosingContextManager):
"""
Transport._modulus_pack = ModulusPack()
# 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:
@@ -682,7 +720,7 @@ class Transport(threading.Thread, ClosingContextManager):
:return: public key (`.PKey`) of the remote server
"""
if (not self.active) or (not self.initial_kex_done):
- raise SSHException('No existing session')
+ raise SSHException("No existing session")
return self.host_key
def is_active(self):
@@ -696,10 +734,7 @@ class Transport(threading.Thread, ClosingContextManager):
return self.active
def open_session(
- self,
- window_size=None,
- max_packet_size=None,
- timeout=None,
+ self, window_size=None, max_packet_size=None, timeout=None
):
"""
Request a new channel to the server, of type ``"session"``. This is
@@ -726,10 +761,12 @@ class Transport(threading.Thread, ClosingContextManager):
.. versionchanged:: 1.15
Added the ``window_size`` and ``max_packet_size`` arguments.
"""
- return self.open_channel('session',
- window_size=window_size,
- max_packet_size=max_packet_size,
- timeout=timeout)
+ return self.open_channel(
+ "session",
+ window_size=window_size,
+ max_packet_size=max_packet_size,
+ timeout=timeout,
+ )
def open_x11_channel(self, src_addr=None):
"""
@@ -745,7 +782,7 @@ class Transport(threading.Thread, ClosingContextManager):
`.SSHException` -- if the request is rejected or the session ends
prematurely
"""
- return self.open_channel('x11', src_addr=src_addr)
+ return self.open_channel("x11", src_addr=src_addr)
def open_forward_agent_channel(self):
"""
@@ -759,7 +796,7 @@ class Transport(threading.Thread, ClosingContextManager):
:raises: `.SSHException` --
if the request is rejected or the session ends prematurely
"""
- return self.open_channel('auth-agent@openssh.com')
+ return self.open_channel("auth-agent@openssh.com")
def open_forwarded_tcpip_channel(self, src_addr, dest_addr):
"""
@@ -771,15 +808,17 @@ class Transport(threading.Thread, ClosingContextManager):
:param src_addr: originator's address
:param dest_addr: local (server) connected address
"""
- return self.open_channel('forwarded-tcpip', dest_addr, src_addr)
+ return self.open_channel("forwarded-tcpip", dest_addr, src_addr)
- def open_channel(self,
- kind,
- dest_addr=None,
- src_addr=None,
- window_size=None,
- max_packet_size=None,
- timeout=None):
+ def open_channel(
+ self,
+ kind,
+ dest_addr=None,
+ src_addr=None,
+ window_size=None,
+ max_packet_size=None,
+ timeout=None,
+ ):
"""
Request a new channel to the server. `Channels <.Channel>` are
socket-like objects used for the actual transfer of data across the
@@ -816,7 +855,7 @@ class Transport(threading.Thread, ClosingContextManager):
Added the ``window_size`` and ``max_packet_size`` arguments.
"""
if not self.active:
- raise SSHException('SSH session not active')
+ raise SSHException("SSH session not active")
timeout = 3600 if timeout is None else timeout
self.lock.acquire()
try:
@@ -829,12 +868,12 @@ class Transport(threading.Thread, ClosingContextManager):
m.add_int(chanid)
m.add_int(window_size)
m.add_int(max_packet_size)
- if (kind == 'forwarded-tcpip') or (kind == 'direct-tcpip'):
+ if (kind == "forwarded-tcpip") or (kind == "direct-tcpip"):
m.add_string(dest_addr[0])
m.add_int(dest_addr[1])
m.add_string(src_addr[0])
m.add_int(src_addr[1])
- elif kind == 'x11':
+ elif kind == "x11":
m.add_string(src_addr[0])
m.add_int(src_addr[1])
chan = Channel(chanid)
@@ -852,18 +891,18 @@ class Transport(threading.Thread, ClosingContextManager):
if not self.active:
e = self.get_exception()
if e is None:
- e = SSHException('Unable to open channel.')
+ e = SSHException("Unable to open channel.")
raise e
if event.is_set():
break
elif start_ts + timeout < time.time():
- raise SSHException('Timeout opening channel.')
+ raise SSHException("Timeout opening channel.")
chan = self._channels.get(chanid)
if chan is not None:
return chan
e = self.get_exception()
if e is None:
- e = SSHException('Unable to open channel.')
+ e = SSHException("Unable to open channel.")
raise e
def request_port_forward(self, address, port, handler=None):
@@ -900,20 +939,22 @@ class Transport(threading.Thread, ClosingContextManager):
`.SSHException` -- if the server refused the TCP forward request
"""
if not self.active:
- raise SSHException('SSH session not active')
+ raise SSHException("SSH session not active")
port = int(port)
response = self.global_request(
- 'tcpip-forward', (address, port), wait=True
+ "tcpip-forward", (address, port), wait=True
)
if response is None:
- raise SSHException('TCP forwarding request denied')
+ raise SSHException("TCP forwarding request denied")
if port == 0:
port = response.get_int()
if handler is None:
+
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
return port
@@ -930,7 +971,7 @@ class Transport(threading.Thread, ClosingContextManager):
if not self.active:
return
self._tcp_handler = None
- self.global_request('cancel-tcpip-forward', (address, port), wait=True)
+ self.global_request("cancel-tcpip-forward", (address, port), wait=True)
def open_sftp_client(self):
"""
@@ -983,7 +1024,7 @@ class Transport(threading.Thread, ClosingContextManager):
e = self.get_exception()
if e is not None:
raise e
- raise SSHException('Negotiation failed.')
+ raise SSHException("Negotiation failed.")
if self.completion_event.is_set():
break
return
@@ -999,8 +1040,10 @@ class Transport(threading.Thread, ClosingContextManager):
seconds to wait before sending a keepalive packet (or
0 to disable keepalives).
"""
+
def _request(x=weakref.proxy(self)):
- return x.global_request('keepalive@lag.net', wait=False)
+ return x.global_request("keepalive@lag.net", wait=False)
+
self.packetizer.set_keepalive(interval, _request)
def global_request(self, kind, data=None, wait=True):
@@ -1068,7 +1111,7 @@ class Transport(threading.Thread, ClosingContextManager):
def connect(
self,
hostkey=None,
- username='',
+ username="",
password=None,
pkey=None,
gss_host=None,
@@ -1128,31 +1171,36 @@ class Transport(threading.Thread, ClosingContextManager):
if (hostkey is not None) and not gss_kex:
key = self.get_remote_server_key()
if (
- key.get_name() != hostkey.get_name() or
- key.asbytes() != hostkey.asbytes()
+ 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(hostkey.asbytes()))
+ self._log(DEBUG, "Bad host key from server")
+ self._log(
+ DEBUG,
+ "Expected: %s: %s"
+ % (hostkey.get_name(), repr(hostkey.asbytes())),
)
- self._log(DEBUG, 'Got : %s: %s' % (
- key.get_name(), repr(key.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())
+ raise SSHException("Bad host key from server")
+ self._log(DEBUG, "Host key verified (%s)" % hostkey.get_name())
if (pkey is not None) or (password is not None) or gss_auth or gss_kex:
if gss_auth:
- self._log(DEBUG, 'Attempting GSS-API auth... (gssapi-with-mic)') # noqa
+ self._log(
+ DEBUG, "Attempting GSS-API auth... (gssapi-with-mic)"
+ ) # noqa
self.auth_gssapi_with_mic(username, gss_host, gss_deleg_creds)
elif gss_kex:
- self._log(DEBUG, 'Attempting GSS-API auth... (gssapi-keyex)')
+ self._log(DEBUG, "Attempting GSS-API auth... (gssapi-keyex)")
self.auth_gssapi_keyex(username)
elif pkey is not None:
- self._log(DEBUG, 'Attempting public-key auth...')
+ self._log(DEBUG, "Attempting public-key auth...")
self.auth_publickey(username, pkey)
else:
- self._log(DEBUG, 'Attempting password auth...')
+ self._log(DEBUG, "Attempting password auth...")
self.auth_password(username, password)
return
@@ -1207,9 +1255,9 @@ class Transport(threading.Thread, ClosingContextManager):
closed.
"""
return (
- self.active and
- self.auth_handler is not None and
- self.auth_handler.is_authenticated()
+ self.active
+ and self.auth_handler is not None
+ and self.auth_handler.is_authenticated()
)
def get_username(self):
@@ -1259,7 +1307,7 @@ class Transport(threading.Thread, ClosingContextManager):
.. versionadded:: 1.5
"""
if (not self.active) or (not self.initial_kex_done):
- raise SSHException('No existing session')
+ raise SSHException("No existing session")
my_event = threading.Event()
self.auth_handler = AuthHandler(self)
self.auth_handler.auth_none(username, my_event)
@@ -1315,7 +1363,7 @@ class Transport(threading.Thread, ClosingContextManager):
if (not self.active) or (not self.initial_kex_done):
# we should never try to send the password unless we're on a secure
# link
- raise SSHException('No existing session')
+ raise SSHException("No existing session")
if event is None:
my_event = threading.Event()
else:
@@ -1330,12 +1378,13 @@ class Transport(threading.Thread, ClosingContextManager):
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 e.allowed_types):
+ if not fallback or ("keyboard-interactive" not in e.allowed_types):
raise
try:
+
def handler(title, instructions, fields):
if len(fields) > 1:
- raise SSHException('Fallback authentication failed.')
+ raise SSHException("Fallback authentication failed.")
if len(fields) == 0:
# for some reason, at least on os x, a 2nd request will
# be made with zero fields requested. maybe it's just
@@ -1343,6 +1392,7 @@ class Transport(threading.Thread, ClosingContextManager):
# type we're doing here. *shrug* :)
return []
return [password]
+
return self.auth_interactive(username, handler)
except SSHException:
# attempt failed; just raise the original exception
@@ -1385,7 +1435,7 @@ class Transport(threading.Thread, ClosingContextManager):
"""
if (not self.active) or (not self.initial_kex_done):
# we should never try to authenticate unless we're on a secure link
- raise SSHException('No existing session')
+ raise SSHException("No existing session")
if event is None:
my_event = threading.Event()
else:
@@ -1397,7 +1447,7 @@ class Transport(threading.Thread, ClosingContextManager):
return []
return self.auth_handler.wait_for_response(my_event)
- def auth_interactive(self, username, handler, submethods=''):
+ def auth_interactive(self, username, handler, submethods=""):
"""
Authenticate to the server interactively. A handler is used to answer
arbitrary questions from the server. On many servers, this is just a
@@ -1442,7 +1492,7 @@ class Transport(threading.Thread, ClosingContextManager):
"""
if (not self.active) or (not self.initial_kex_done):
# we should never try to authenticate unless we're on a secure link
- raise SSHException('No existing session')
+ raise SSHException("No existing session")
my_event = threading.Event()
self.auth_handler = AuthHandler(self)
self.auth_handler.auth_interactive(
@@ -1450,7 +1500,7 @@ class Transport(threading.Thread, ClosingContextManager):
)
return self.auth_handler.wait_for_response(my_event)
- def auth_interactive_dumb(self, username, handler=None, submethods=''):
+ def auth_interactive_dumb(self, username, handler=None, submethods=""):
"""
Autenticate to the server interactively but dumber.
Just print the prompt and / or instructions to stdout and send back
@@ -1459,6 +1509,7 @@ class Transport(threading.Thread, ClosingContextManager):
"""
if not handler:
+
def handler(title, instructions, prompt_list):
answers = []
if title:
@@ -1466,9 +1517,10 @@ class Transport(threading.Thread, ClosingContextManager):
if instructions:
print(instructions.strip())
for prompt, show_input in prompt_list:
- print(prompt.strip(), end=' ')
+ print(prompt.strip(), end=" ")
answers.append(input())
return answers
+
return self.auth_interactive(username, handler, submethods)
def auth_gssapi_with_mic(self, username, gss_host, gss_deleg_creds):
@@ -1490,7 +1542,7 @@ class Transport(threading.Thread, ClosingContextManager):
"""
if (not self.active) or (not self.initial_kex_done):
# we should never try to authenticate unless we're on a secure link
- raise SSHException('No existing session')
+ raise SSHException("No existing session")
my_event = threading.Event()
self.auth_handler = AuthHandler(self)
self.auth_handler.auth_gssapi_with_mic(
@@ -1515,7 +1567,7 @@ class Transport(threading.Thread, ClosingContextManager):
"""
if (not self.active) or (not self.initial_kex_done):
# we should never try to authenticate unless we're on a secure link
- raise SSHException('No existing session')
+ raise SSHException("No existing session")
my_event = threading.Event()
self.auth_handler = AuthHandler(self)
self.auth_handler.auth_gssapi_keyex(username, my_event)
@@ -1582,9 +1634,9 @@ class Transport(threading.Thread, ClosingContextManager):
.. 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):
"""
@@ -1598,9 +1650,9 @@ class Transport(threading.Thread, ClosingContextManager):
the address of the remote host, if known, as a ``(str, int)``
tuple.
"""
- gp = getattr(self.sock, 'getpeername', None)
+ gp = getattr(self.sock, "getpeername", None)
if gp is None:
- return 'unknown', 0
+ return "unknown", 0
return gp()
def stop_thread(self):
@@ -1619,10 +1671,10 @@ class Transport(threading.Thread, ClosingContextManager):
# our socket and packetizer are both closed (but where we'd
# otherwise be sitting forever on that recv()).
while (
- self.is_alive() and
- self is not threading.current_thread() and
- not self.sock._closed and
- not self.packetizer.closed
+ self.is_alive()
+ and self is not threading.current_thread()
+ and not self.sock._closed
+ and not self.packetizer.closed
):
self.join(0.1)
@@ -1664,14 +1716,18 @@ class Transport(threading.Thread, ClosingContextManager):
while True:
self.clear_to_send.wait(0.1)
if not self.active:
- self._log(DEBUG, 'Dropping user packet because connection is dead.') # noqa
+ self._log(
+ DEBUG, "Dropping user packet because connection is dead."
+ ) # noqa
return
self.clear_to_send_lock.acquire()
if self.clear_to_send.is_set():
break
self.clear_to_send_lock.release()
if time.time() > start + self.clear_to_send_timeout:
- raise SSHException('Key-exchange timed out waiting for key negotiation') # noqa
+ raise SSHException(
+ "Key-exchange timed out waiting for key negotiation"
+ ) # noqa
try:
self._send_message(data)
finally:
@@ -1695,9 +1751,11 @@ class Transport(threading.Thread, ClosingContextManager):
def _verify_key(self, host_key, sig):
key = self._key_info[self.host_key_type](Message(host_key))
if key is None:
- raise SSHException('Unknown host key type')
+ raise SSHException("Unknown host key type")
if not key.verify_ssh_sig(self.H, Message(sig)):
- raise SSHException('Signature verification (%s) failed.' % self.host_key_type) # noqa
+ raise SSHException(
+ "Signature verification (%s) failed." % self.host_key_type
+ ) # noqa
self.host_key = key
def _compute_key(self, id, nbytes):
@@ -1709,16 +1767,17 @@ class Transport(threading.Thread, ClosingContextManager):
m.add_bytes(self.session_id)
# Fallback to SHA1 for kex engines that fail to specify a hex
# algorithm, or for e.g. transport tests that don't run kexinit.
- hash_algo = getattr(self.kex_engine, 'hash_algo', None)
+ hash_algo = getattr(self.kex_engine, "hash_algo", None)
hash_select_msg = "kex engine %s specified hash_algo %r" % (
- self.kex_engine.__class__.__name__, hash_algo
+ self.kex_engine.__class__.__name__,
+ hash_algo,
)
if hash_algo is None:
hash_algo = sha1
hash_select_msg += ", falling back to sha1"
- if not hasattr(self, '_logged_hash_selection'):
+ if not hasattr(self, "_logged_hash_selection"):
self._log(DEBUG, hash_select_msg)
- setattr(self, '_logged_hash_selection', True)
+ setattr(self, "_logged_hash_selection", True)
out = sofar = hash_algo(m.asbytes()).digest()
while len(out) < nbytes:
m = Message()
@@ -1732,11 +1791,11 @@ class Transport(threading.Thread, ClosingContextManager):
def _get_cipher(self, name, key, iv, operation):
if name not in self._cipher_info:
- raise SSHException('Unknown client cipher ' + name)
+ raise SSHException("Unknown client cipher " + name)
else:
cipher = Cipher(
- self._cipher_info[name]['class'](key),
- self._cipher_info[name]['mode'](iv),
+ self._cipher_info[name]["class"](key),
+ self._cipher_info[name]["mode"](iv),
backend=default_backend(),
)
if operation is self._ENCRYPT:
@@ -1746,8 +1805,10 @@ class Transport(threading.Thread, ClosingContextManager):
def _set_forward_agent_handler(self, handler):
if handler is None:
+
def default_handler(channel):
self._queue_incoming_channel(channel)
+
self._forward_agent_handler = default_handler
else:
self._forward_agent_handler = handler
@@ -1758,6 +1819,7 @@ class Transport(threading.Thread, ClosingContextManager):
# by default, use the same mechanism as accept()
def default_handler(channel, src_addr_port):
self._queue_incoming_channel(channel)
+
self._x11_handler = default_handler
else:
self._x11_handler = handler
@@ -1791,9 +1853,9 @@ class Transport(threading.Thread, ClosingContextManager):
Otherwise (client mode, authed, or pre-auth message) returns None.
"""
if (
- not self.server_mode or
- ptype <= HIGHEST_USERAUTH_MESSAGE_ID or
- self.is_authenticated()
+ not self.server_mode
+ or ptype <= HIGHEST_USERAUTH_MESSAGE_ID
+ or self.is_authenticated()
):
return None
# WELP. We must be dealing with someone trying to do non-auth things
@@ -1804,13 +1866,13 @@ class Transport(threading.Thread, ClosingContextManager):
reply.add_byte(cMSG_REQUEST_FAILURE)
# Channel opens let us reject w/ a specific type + message.
elif ptype == MSG_CHANNEL_OPEN:
- kind = message.get_text() # noqa
+ kind = message.get_text() # noqa
chanid = message.get_int()
reply.add_byte(cMSG_CHANNEL_OPEN_FAILURE)
reply.add_int(chanid)
reply.add_int(OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED)
- reply.add_string('')
- reply.add_string('en')
+ reply.add_string("")
+ reply.add_string("en")
# NOTE: Post-open channel messages do not need checking; the above will
# reject attemps to open channels, meaning that even if a malicious
# user tries to send a MSG_CHANNEL_REQUEST, it will simply fall under
@@ -1832,13 +1894,15 @@ class Transport(threading.Thread, ClosingContextManager):
_active_threads.append(self)
tid = hex(long(id(self)) & xffffffff)
if self.server_mode:
- self._log(DEBUG, 'starting thread (server mode): %s' % tid)
+ self._log(DEBUG, "starting thread (server mode): %s" % tid)
else:
- self._log(DEBUG, 'starting thread (client mode): %s' % tid)
+ self._log(DEBUG, "starting thread (client mode): %s" % tid)
try:
try:
- self.packetizer.write_all(b(self.local_version + '\r\n'))
- self._log(DEBUG, 'Local version/idstring: %s' % self.local_version) # noqa
+ self.packetizer.write_all(b(self.local_version + "\r\n"))
+ self._log(
+ DEBUG, "Local version/idstring: %s" % self.local_version
+ ) # noqa
self._check_banner()
# The above is actually very much part of the handshake, but
# sometimes the banner can be read but the machine is not
@@ -1870,7 +1934,10 @@ class Transport(threading.Thread, ClosingContextManager):
continue
if len(self._expected_packet) > 0:
if ptype not in self._expected_packet:
- raise SSHException('Expecting packet from %r, got %d' % (self._expected_packet, ptype)) # noqa
+ raise SSHException(
+ "Expecting packet from %r, got %d"
+ % (self._expected_packet, ptype)
+ ) # noqa
self._expected_packet = tuple()
if (ptype >= 30) and (ptype <= 41):
self.kex_engine.parse_next(ptype, m)
@@ -1888,45 +1955,53 @@ class Transport(threading.Thread, ClosingContextManager):
if chan is not None:
self._channel_handler_table[ptype](chan, m)
elif chanid in self.channels_seen:
- self._log(DEBUG, 'Ignoring message for dead channel %d' % chanid) # noqa
+ self._log(
+ DEBUG,
+ "Ignoring message for dead channel %d"
+ % chanid,
+ ) # noqa
else:
- self._log(ERROR, 'Channel request for unknown channel %d' % chanid) # noqa
+ self._log(
+ ERROR,
+ "Channel request for unknown channel %d"
+ % chanid,
+ ) # noqa
self.active = False
self.packetizer.close()
elif (
- self.auth_handler is not None and
- ptype in self.auth_handler._handler_table
+ self.auth_handler is not None
+ and ptype in self.auth_handler._handler_table
):
handler = self.auth_handler._handler_table[ptype]
handler(self.auth_handler, m)
if len(self._expected_packet) > 0:
continue
else:
- self._log(WARNING, 'Oops, unhandled type %d' % ptype)
+ self._log(WARNING, "Oops, unhandled type %d" % ptype)
msg = Message()
msg.add_byte(cMSG_UNIMPLEMENTED)
msg.add_int(m.seqno)
self._send_message(msg)
self.packetizer.complete_handshake()
except SSHException as e:
- self._log(ERROR, 'Exception: ' + str(e))
+ self._log(ERROR, "Exception: " + str(e))
self._log(ERROR, util.tb_strings())
self.saved_exception = e
except EOFError as e:
- self._log(DEBUG, 'EOF in transport thread')
+ self._log(DEBUG, "EOF in transport thread")
self.saved_exception = e
except socket.error as e:
if type(e.args) is tuple:
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
emsg = str(e) or repr(e)
else:
emsg = e.args
- self._log(ERROR, 'Socket exception: ' + emsg)
+ self._log(ERROR, "Socket exception: " + emsg)
self.saved_exception = e
except Exception as e:
- self._log(ERROR, 'Unknown exception: ' + str(e))
+ self._log(ERROR, "Unknown exception: " + str(e))
self._log(ERROR, util.tb_strings())
self.saved_exception = e
_active_threads.remove(self)
@@ -1955,7 +2030,6 @@ class Transport(threading.Thread, ClosingContextManager):
if self.sys.modules is not None:
raise
-
def _log_agreement(self, which, local, remote):
# Log useful, non-duplicative line re: an agreed-upon algorithm.
# Old code implied algorithms could be asymmetrical (different for
@@ -1997,32 +2071,32 @@ class Transport(threading.Thread, ClosingContextManager):
raise
except Exception as e:
raise SSHException(
- 'Error reading SSH protocol banner' + str(e)
+ "Error reading SSH protocol banner" + str(e)
)
- if buf[:4] == 'SSH-':
+ if buf[:4] == "SSH-":
break
- self._log(DEBUG, 'Banner: ' + buf)
- if buf[:4] != 'SSH-':
+ self._log(DEBUG, "Banner: " + buf)
+ if buf[:4] != "SSH-":
raise SSHException('Indecipherable protocol version "' + buf + '"')
# save this server version string for later
self.remote_version = buf
- self._log(DEBUG, 'Remote version/idstring: %s' % buf)
+ self._log(DEBUG, "Remote version/idstring: %s" % buf)
# pull off any attached comment
# NOTE: comment used to be stored in a variable and then...never used.
# since 2003. ca 877cd974b8182d26fa76d566072917ea67b64e67
- i = buf.find(' ')
+ i = buf.find(" ")
if i >= 0:
buf = buf[:i]
# parse out version string and make sure it matches
- segs = buf.split('-', 2)
+ segs = buf.split("-", 2)
if len(segs) < 3:
- raise SSHException('Invalid SSH banner')
+ raise SSHException("Invalid SSH banner")
version = segs[1]
client = segs[2]
- if version != '1.99' and version != '2.0':
- msg = 'Incompatible version ({0} instead of 2.0)'
+ if version != "1.99" and version != "2.0":
+ msg = "Incompatible version ({0} instead of 2.0)"
raise SSHException(msg.format(version))
- msg = 'Connected (version {0}, client {1})'.format(version, client)
+ msg = "Connected (version {0}, client {1})".format(version, client)
self._log(INFO, msg)
def _send_kex_init(self):
@@ -2038,25 +2112,27 @@ class Transport(threading.Thread, ClosingContextManager):
self.gss_kex_used = False
self.in_kex = True
if self.server_mode:
- mp_required_prefix = 'diffie-hellman-group-exchange-sha'
+ mp_required_prefix = "diffie-hellman-group-exchange-sha"
kex_mp = [
- k for k
- in self._preferred_kex
+ k
+ for k in self._preferred_kex
if k.startswith(mp_required_prefix)
]
if (self._modulus_pack is None) and (len(kex_mp) > 0):
# can't do group-exchange if we don't have a pack of potential
# primes
pkex = [
- k for k
- in self.get_security_options().kex
+ k
+ for k in self.get_security_options().kex
if not k.startswith(mp_required_prefix)
]
self.get_security_options().kex = pkex
- available_server_keys = list(filter(
- list(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
@@ -2080,7 +2156,7 @@ class Transport(threading.Thread, ClosingContextManager):
self._send_message(m)
def _parse_kex_init(self, m):
- m.get_bytes(16) # cookie, discarded
+ m.get_bytes(16) # cookie, discarded
kex_algo_list = m.get_list()
server_key_algo_list = m.get_list()
client_encrypt_algo_list = m.get_list()
@@ -2092,20 +2168,32 @@ class Transport(threading.Thread, ClosingContextManager):
client_lang_list = m.get_list()
server_lang_list = m.get_list()
kex_follows = m.get_boolean()
- m.get_int() # unused
-
- 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)
+ m.get_int() # unused
+
+ 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
@@ -2113,122 +2201,149 @@ class Transport(threading.Thread, ClosingContextManager):
# as a client, we pick the first item in our list that the server
# supports.
if self.server_mode:
- agreed_kex = list(filter(
- self._preferred_kex.__contains__,
- kex_algo_list
- ))
+ agreed_kex = list(
+ filter(self._preferred_kex.__contains__, kex_algo_list)
+ )
else:
- agreed_kex = list(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)') # noqa
+ raise SSHException(
+ "Incompatible ssh peer (no acceptable kex algorithm)"
+ ) # noqa
self.kex_engine = self._kex_info[agreed_kex[0]](self)
self._log(DEBUG, "Kex agreed: %s" % agreed_kex[0])
if self.server_mode:
- 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
- ))
+ 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 = list(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)') # noqa
+ raise SSHException(
+ "Incompatible ssh peer (no acceptable host key)"
+ ) # noqa
self.host_key_type = agreed_keys[0]
if self.server_mode and (self.get_server_key() is None):
- raise SSHException('Incompatible ssh peer (can\'t match requested host key type)') # noqa
- self._log_agreement(
- 'HostKey', agreed_keys[0], agreed_keys[0]
- )
+ raise SSHException(
+ "Incompatible ssh peer (can't match requested host key type)"
+ ) # noqa
+ self._log_agreement("HostKey", agreed_keys[0], agreed_keys[0])
if self.server_mode:
- 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
- ))
+ 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 = list(filter(
- client_encrypt_algo_list.__contains__,
- self._preferred_ciphers
- ))
- agreed_remote_ciphers = list(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)') # noqa
+ raise SSHException(
+ "Incompatible ssh server (no acceptable ciphers)"
+ ) # noqa
self.local_cipher = agreed_local_ciphers[0]
self.remote_cipher = agreed_remote_ciphers[0]
self._log_agreement(
- 'Cipher', local=self.local_cipher, remote=self.remote_cipher
+ "Cipher", local=self.local_cipher, remote=self.remote_cipher
)
if self.server_mode:
- 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
- ))
+ 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 = list(filter(
- client_mac_algo_list.__contains__, self._preferred_macs
- ))
- agreed_remote_macs = list(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)')
+ raise SSHException("Incompatible ssh server (no acceptable macs)")
self.local_mac = agreed_local_macs[0]
self.remote_mac = agreed_remote_macs[0]
self._log_agreement(
- 'MAC', local=self.local_mac, remote=self.remote_mac
+ "MAC", local=self.local_mac, remote=self.remote_mac
)
if self.server_mode:
- 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
- ))
+ 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 = list(filter(
- client_compress_algo_list.__contains__,
- self._preferred_compression
- ))
- agreed_remote_compression = list(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
+ len(agreed_local_compression) == 0
+ or len(agreed_remote_compression) == 0
):
- msg = 'Incompatible ssh server (no acceptable compression) {0!r} {1!r} {2!r}' # noqa
- raise SSHException(msg.format(
- agreed_local_compression, agreed_remote_compression,
- self._preferred_compression,
- ))
+ msg = "Incompatible ssh server (no acceptable compression) {0!r} {1!r} {2!r}" # noqa
+ raise SSHException(
+ msg.format(
+ agreed_local_compression,
+ agreed_remote_compression,
+ self._preferred_compression,
+ )
+ )
self.local_compression = agreed_local_compression[0]
self.remote_compression = agreed_remote_compression[0]
self._log_agreement(
- 'Compression',
+ "Compression",
local=self.local_compression,
- remote=self.remote_compression
+ remote=self.remote_compression,
)
# save for computing hash later...
@@ -2241,40 +2356,36 @@ class Transport(threading.Thread, ClosingContextManager):
def _activate_inbound(self):
"""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:
- IV_in = self._compute_key('A', block_size)
+ IV_in = self._compute_key("A", block_size)
key_in = self._compute_key(
- 'C', self._cipher_info[self.remote_cipher]['key-size']
+ "C", self._cipher_info[self.remote_cipher]["key-size"]
)
else:
- IV_in = self._compute_key('B', block_size)
+ IV_in = self._compute_key("B", block_size)
key_in = self._compute_key(
- 'D', self._cipher_info[self.remote_cipher]['key-size']
+ "D", self._cipher_info[self.remote_cipher]["key-size"]
)
engine = self._get_cipher(
self.remote_cipher, key_in, IV_in, self._DECRYPT
)
- mac_size = self._mac_info[self.remote_mac]['size']
- mac_engine = self._mac_info[self.remote_mac]['class']
+ mac_size = self._mac_info[self.remote_mac]["size"]
+ mac_engine = self._mac_info[self.remote_mac]["class"]
# initial mac keys are done in the hash's natural size (not the
# potentially truncated transmission size)
if self.server_mode:
- mac_key = self._compute_key('E', mac_engine().digest_size)
+ mac_key = self._compute_key("E", mac_engine().digest_size)
else:
- mac_key = self._compute_key('F', mac_engine().digest_size)
+ mac_key = self._compute_key("F", mac_engine().digest_size)
self.packetizer.set_inbound_cipher(
engine, block_size, mac_engine, mac_size, mac_key
)
compress_in = self._compression_info[self.remote_compression][1]
- if (
- compress_in is not None and
- (
- self.remote_compression != 'zlib@openssh.com' or
- self.authenticated
- )
+ if compress_in is not None and (
+ self.remote_compression != "zlib@openssh.com" or self.authenticated
):
- self._log(DEBUG, 'Switching on inbound compression ...')
+ self._log(DEBUG, "Switching on inbound compression ...")
self.packetizer.set_inbound_compressor(compress_in())
def _activate_outbound(self):
@@ -2283,37 +2394,37 @@ class Transport(threading.Thread, ClosingContextManager):
m = Message()
m.add_byte(cMSG_NEWKEYS)
self._send_message(m)
- block_size = self._cipher_info[self.local_cipher]['block-size']
+ block_size = self._cipher_info[self.local_cipher]["block-size"]
if self.server_mode:
- IV_out = self._compute_key('B', block_size)
+ IV_out = self._compute_key("B", block_size)
key_out = self._compute_key(
- 'D', self._cipher_info[self.local_cipher]['key-size'])
+ "D", self._cipher_info[self.local_cipher]["key-size"]
+ )
else:
- IV_out = self._compute_key('A', block_size)
+ IV_out = self._compute_key("A", block_size)
key_out = self._compute_key(
- 'C', self._cipher_info[self.local_cipher]['key-size'])
+ "C", self._cipher_info[self.local_cipher]["key-size"]
+ )
engine = self._get_cipher(
- self.local_cipher, key_out, IV_out, self._ENCRYPT)
- mac_size = self._mac_info[self.local_mac]['size']
- mac_engine = self._mac_info[self.local_mac]['class']
+ self.local_cipher, key_out, IV_out, self._ENCRYPT
+ )
+ mac_size = self._mac_info[self.local_mac]["size"]
+ mac_engine = self._mac_info[self.local_mac]["class"]
# initial mac keys are done in the hash's natural size (not the
# potentially truncated transmission size)
if self.server_mode:
- mac_key = self._compute_key('F', mac_engine().digest_size)
+ mac_key = self._compute_key("F", mac_engine().digest_size)
else:
- mac_key = self._compute_key('E', mac_engine().digest_size)
- sdctr = self.local_cipher.endswith('-ctr')
+ mac_key = self._compute_key("E", mac_engine().digest_size)
+ sdctr = self.local_cipher.endswith("-ctr")
self.packetizer.set_outbound_cipher(
- engine, block_size, mac_engine, mac_size, mac_key, sdctr)
+ engine, block_size, mac_engine, mac_size, mac_key, sdctr
+ )
compress_out = self._compression_info[self.local_compression][0]
- if (
- compress_out is not None and
- (
- self.local_compression != 'zlib@openssh.com' or
- self.authenticated
- )
+ if compress_out is not None and (
+ self.local_compression != "zlib@openssh.com" or self.authenticated
):
- self._log(DEBUG, 'Switching on outbound compression ...')
+ self._log(DEBUG, "Switching on outbound compression ...")
self.packetizer.set_outbound_compressor(compress_out())
if not self.packetizer.need_rekey():
self.in_kex = False
@@ -2323,17 +2434,17 @@ class Transport(threading.Thread, ClosingContextManager):
def _auth_trigger(self):
self.authenticated = True
# delayed initiation of compression
- if self.local_compression == 'zlib@openssh.com':
+ if self.local_compression == "zlib@openssh.com":
compress_out = self._compression_info[self.local_compression][0]
- self._log(DEBUG, 'Switching on outbound compression ...')
+ self._log(DEBUG, "Switching on outbound compression ...")
self.packetizer.set_outbound_compressor(compress_out())
- if self.remote_compression == 'zlib@openssh.com':
+ if self.remote_compression == "zlib@openssh.com":
compress_in = self._compression_info[self.remote_compression][1]
- self._log(DEBUG, 'Switching on inbound compression ...')
+ self._log(DEBUG, "Switching on inbound compression ...")
self.packetizer.set_inbound_compressor(compress_in())
def _parse_newkeys(self, m):
- self._log(DEBUG, 'Switch to new keys ...')
+ self._log(DEBUG, "Switch to new keys ...")
self._activate_inbound()
# can also free a bunch of stuff here
self.local_kex_init = self.remote_kex_init = None
@@ -2361,7 +2472,7 @@ class Transport(threading.Thread, ClosingContextManager):
def _parse_disconnect(self, m):
code = m.get_int()
desc = m.get_text()
- self._log(INFO, 'Disconnect (code %d): %s' % (code, desc))
+ self._log(INFO, "Disconnect (code %d): %s" % (code, desc))
def _parse_global_request(self, m):
kind = m.get_text()
@@ -2369,17 +2480,16 @@ class Transport(threading.Thread, ClosingContextManager):
want_reply = m.get_boolean()
if not self.server_mode:
self._log(
- DEBUG,
- 'Rejecting "%s" global request from server.' % kind
+ DEBUG, 'Rejecting "%s" global request from server.' % kind
)
ok = False
- elif kind == 'tcpip-forward':
+ elif kind == "tcpip-forward":
address = m.get_text()
port = m.get_int()
ok = self.server_object.check_port_forward_request(address, port)
if ok:
ok = (ok,)
- elif kind == 'cancel-tcpip-forward':
+ elif kind == "cancel-tcpip-forward":
address = m.get_text()
port = m.get_int()
self.server_object.cancel_port_forward_request(address, port)
@@ -2400,13 +2510,13 @@ class Transport(threading.Thread, ClosingContextManager):
self._send_message(msg)
def _parse_request_success(self, m):
- self._log(DEBUG, 'Global request successful.')
+ self._log(DEBUG, "Global request successful.")
self.global_response = m
if self.completion_event is not None:
self.completion_event.set()
def _parse_request_failure(self, m):
- self._log(DEBUG, 'Global request denied.')
+ self._log(DEBUG, "Global request denied.")
self.global_response = None
if self.completion_event is not None:
self.completion_event.set()
@@ -2418,13 +2528,14 @@ class Transport(threading.Thread, ClosingContextManager):
server_max_packet_size = m.get_int()
chan = self._channels.get(chanid)
if chan is None:
- self._log(WARNING, 'Success for unrequested channel! [??]')
+ self._log(WARNING, "Success for unrequested channel! [??]")
return
self.lock.acquire()
try:
chan._set_remote_channel(
- server_chanid, server_window_size, server_max_packet_size)
- self._log(DEBUG, 'Secsh channel %d opened.' % chanid)
+ server_chanid, server_window_size, server_max_packet_size
+ )
+ self._log(DEBUG, "Secsh channel %d opened." % chanid)
if chanid in self.channel_events:
self.channel_events[chanid].set()
del self.channel_events[chanid]
@@ -2437,11 +2548,11 @@ class Transport(threading.Thread, ClosingContextManager):
reason = m.get_int()
reason_str = m.get_text()
m.get_text() # ignored language
- reason_text = CONNECTION_FAILED_CODE.get(reason, '(unknown code)')
+ reason_text = CONNECTION_FAILED_CODE.get(reason, "(unknown code)")
self._log(
ERROR,
- 'Secsh channel %d open FAILED: %s: %s' % (
- chanid, reason_str, reason_text)
+ "Secsh channel %d open FAILED: %s: %s"
+ % (chanid, reason_str, reason_text),
)
self.lock.acquire()
try:
@@ -2462,37 +2573,37 @@ class Transport(threading.Thread, ClosingContextManager):
max_packet_size = m.get_int()
reject = False
if (
- kind == 'auth-agent@openssh.com' and
- self._forward_agent_handler is not None
+ kind == "auth-agent@openssh.com"
+ and self._forward_agent_handler is not None
):
- self._log(DEBUG, 'Incoming forward agent connection')
+ self._log(DEBUG, "Incoming forward agent connection")
self.lock.acquire()
try:
my_chanid = self._next_channel()
finally:
self.lock.release()
- elif (kind == 'x11') and (self._x11_handler is not None):
+ elif (kind == "x11") and (self._x11_handler is not None):
origin_addr = m.get_text()
origin_port = m.get_int()
self._log(
DEBUG,
- 'Incoming x11 connection from %s:%d' % (
- origin_addr, origin_port)
+ "Incoming x11 connection from %s:%d"
+ % (origin_addr, origin_port),
)
self.lock.acquire()
try:
my_chanid = self._next_channel()
finally:
self.lock.release()
- elif (kind == 'forwarded-tcpip') and (self._tcp_handler is not None):
+ elif (kind == "forwarded-tcpip") and (self._tcp_handler is not None):
server_addr = m.get_text()
server_port = m.get_int()
origin_addr = m.get_text()
origin_port = m.get_int()
self._log(
DEBUG,
- 'Incoming tcp forwarded connection from %s:%d' % (
- origin_addr, origin_port)
+ "Incoming tcp forwarded connection from %s:%d"
+ % (origin_addr, origin_port),
)
self.lock.acquire()
try:
@@ -2501,8 +2612,8 @@ class Transport(threading.Thread, ClosingContextManager):
self.lock.release()
elif not self.server_mode:
self._log(
- DEBUG,
- 'Rejecting "%s" channel request from server.' % kind)
+ DEBUG, 'Rejecting "%s" channel request from server.' % kind
+ )
reject = True
reason = OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED
else:
@@ -2511,7 +2622,7 @@ class Transport(threading.Thread, ClosingContextManager):
my_chanid = self._next_channel()
finally:
self.lock.release()
- if kind == 'direct-tcpip':
+ if kind == "direct-tcpip":
# handle direct-tcpip requests coming from the client
dest_addr = m.get_text()
dest_port = m.get_int()
@@ -2520,23 +2631,24 @@ class Transport(threading.Thread, ClosingContextManager):
reason = self.server_object.check_channel_direct_tcpip_request(
my_chanid,
(origin_addr, origin_port),
- (dest_addr, dest_port)
+ (dest_addr, dest_port),
)
else:
reason = self.server_object.check_channel_request(
- kind, my_chanid)
+ kind, my_chanid
+ )
if reason != OPEN_SUCCEEDED:
self._log(
- DEBUG,
- 'Rejecting "%s" channel request from client.' % kind)
+ DEBUG, 'Rejecting "%s" channel request from client.' % kind
+ )
reject = True
if reject:
msg = Message()
msg.add_byte(cMSG_CHANNEL_OPEN_FAILURE)
msg.add_int(chanid)
msg.add_int(reason)
- msg.add_string('')
- msg.add_string('en')
+ msg.add_string("")
+ msg.add_string("en")
self._send_message(msg)
return
@@ -2547,9 +2659,11 @@ class Transport(threading.Thread, ClosingContextManager):
self.channels_seen[my_chanid] = True
chan._set_transport(self)
chan._set_window(
- self.default_window_size, self.default_max_packet_size)
+ self.default_window_size, self.default_max_packet_size
+ )
chan._set_remote_channel(
- chanid, initial_window_size, max_packet_size)
+ chanid, initial_window_size, max_packet_size
+ )
finally:
self.lock.release()
m = Message()
@@ -2559,17 +2673,15 @@ class Transport(threading.Thread, ClosingContextManager):
m.add_int(self.default_window_size)
m.add_int(self.default_max_packet_size)
self._send_message(m)
- self._log(DEBUG, 'Secsh channel %d (%s) opened.', my_chanid, kind)
- if kind == 'auth-agent@openssh.com':
+ self._log(DEBUG, "Secsh channel %d (%s) opened.", my_chanid, kind)
+ if kind == "auth-agent@openssh.com":
self._forward_agent_handler(chan)
- elif kind == 'x11':
+ elif kind == "x11":
self._x11_handler(chan, (origin_addr, origin_port))
- elif kind == 'forwarded-tcpip':
+ elif kind == "forwarded-tcpip":
chan.origin_addr = (origin_addr, origin_port)
self._tcp_handler(
- chan,
- (origin_addr, origin_port),
- (server_addr, server_port)
+ chan, (origin_addr, origin_port), (server_addr, server_port)
)
else:
self._queue_incoming_channel(chan)
@@ -2578,7 +2690,7 @@ class Transport(threading.Thread, ClosingContextManager):
m.get_boolean() # always_display
msg = m.get_string()
m.get_string() # language
- self._log(DEBUG, 'Debug msg: {0}'.format(util.safe_string(msg)))
+ self._log(DEBUG, "Debug msg: {0}".format(util.safe_string(msg)))
def _get_subsystem_handler(self, name):
try:
@@ -2612,7 +2724,7 @@ class Transport(threading.Thread, ClosingContextManager):
}
-class SecurityOptions (object):
+class SecurityOptions(object):
"""
Simple object containing the security preferences of an ssh transport.
These are tuples of acceptable ciphers, digests, key types, and key
@@ -2624,7 +2736,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__ = '_transport'
+
+ __slots__ = "_transport"
def __init__(self, transport):
self._transport = transport
@@ -2633,17 +2746,17 @@ class SecurityOptions (object):
"""
Returns a string representation of this object, for debugging.
"""
- return '<paramiko.SecurityOptions for %s>' % repr(self._transport)
+ return "<paramiko.SecurityOptions for %s>" % repr(self._transport)
def _set(self, name, orig, x):
if type(x) is list:
x = tuple(x)
if type(x) is not tuple:
- raise TypeError('expected tuple or list')
+ raise TypeError("expected tuple or list")
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')
+ raise ValueError("unknown cipher")
setattr(self._transport, name, x)
@property
@@ -2653,7 +2766,7 @@ class SecurityOptions (object):
@ciphers.setter
def ciphers(self, x):
- self._set('_preferred_ciphers', '_cipher_info', x)
+ self._set("_preferred_ciphers", "_cipher_info", x)
@property
def digests(self):
@@ -2662,7 +2775,7 @@ class SecurityOptions (object):
@digests.setter
def digests(self, x):
- self._set('_preferred_macs', '_mac_info', x)
+ self._set("_preferred_macs", "_mac_info", x)
@property
def key_types(self):
@@ -2671,8 +2784,7 @@ class SecurityOptions (object):
@key_types.setter
def key_types(self, x):
- self._set('_preferred_keys', '_key_info', x)
-
+ self._set("_preferred_keys", "_key_info", x)
@property
def kex(self):
@@ -2681,7 +2793,7 @@ class SecurityOptions (object):
@kex.setter
def kex(self, x):
- self._set('_preferred_kex', '_kex_info', x)
+ self._set("_preferred_kex", "_kex_info", x)
@property
def compression(self):
@@ -2690,10 +2802,10 @@ class SecurityOptions (object):
@compression.setter
def compression(self, x):
- self._set('_preferred_compression', '_compression_info', x)
+ self._set("_preferred_compression", "_compression_info", x)
-class ChannelMap (object):
+class ChannelMap(object):
def __init__(self):
# (id -> Channel)
self._map = weakref.WeakValueDictionary()