summaryrefslogtreecommitdiffhomepage
path: root/paramiko/transport.py
diff options
context:
space:
mode:
Diffstat (limited to 'paramiko/transport.py')
-rw-r--r--paramiko/transport.py623
1 files changed, 421 insertions, 202 deletions
diff --git a/paramiko/transport.py b/paramiko/transport.py
index d6acb4aa..4a3ae8f4 100644
--- a/paramiko/transport.py
+++ b/paramiko/transport.py
@@ -37,34 +37,37 @@ from paramiko import util
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
+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,
+)
from paramiko.compress import ZlibCompressor, ZlibDecompressor
from paramiko.dsskey import DSSKey
from paramiko.kex_gex import KexGex, KexGexSHA256
from paramiko.kex_group1 import KexGroup1
from paramiko.kex_group14 import KexGroup14
-from paramiko.kex_gss import KexGSSGex, KexGSSGroup1, KexGSSGroup14, NullHostKey
+from paramiko.kex_gss import KexGSSGex, KexGSSGroup1, KexGSSGroup14
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, input
+from paramiko.py3compat import string_types, long, byte_ord, b, input, PY2
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)
+from paramiko.ssh_exception import (
+ SSHException, BadAuthenticationType, ChannelException, ProxyCommandFailure,
+)
from paramiko.util import retry_on_signal, ClosingContextManager, clamp_value
@@ -79,7 +82,7 @@ import atexit
atexit.register(_join_lingering_threads)
-class Transport (threading.Thread, ClosingContextManager):
+class Transport(threading.Thread, ClosingContextManager):
"""
An SSH Transport attaches to a stream (usually a socket), negotiates an
encrypted session, authenticates, and then creates stream tunnels, called
@@ -116,11 +119,13 @@ class Transport (threading.Thread, ClosingContextManager):
'hmac-sha1',
)
_preferred_keys = (
+ 'ecdsa-sha2-nistp256',
+ 'ecdsa-sha2-nistp384',
+ 'ecdsa-sha2-nistp521',
'ssh-rsa',
'ssh-dss',
- 'ecdsa-sha2-nistp256',
)
- _preferred_kex = (
+ _preferred_kex = (
'diffie-hellman-group1-sha1',
'diffie-hellman-group14-sha1',
'diffie-hellman-group-exchange-sha1',
@@ -193,6 +198,8 @@ class Transport (threading.Thread, ClosingContextManager):
'ssh-rsa': RSAKey,
'ssh-dss': DSSKey,
'ecdsa-sha2-nistp256': ECDSAKey,
+ 'ecdsa-sha2-nistp384': ECDSAKey,
+ 'ecdsa-sha2-nistp521': ECDSAKey,
}
_kex_info = {
@@ -215,6 +222,7 @@ class Transport (threading.Thread, ClosingContextManager):
}
_modulus_pack = None
+ _active_check_timeout = 0.1
def __init__(self,
sock,
@@ -224,8 +232,8 @@ class Transport (threading.Thread, ClosingContextManager):
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 the
- SSH session yet. Use `connect` or `start_client` to begin a client
+ object. This only creates the `.Transport` object; it doesn't begin
+ the SSH session yet. Use `connect` or `start_client` to begin a client
session, or `start_server` to begin a server session.
If the object is not actually a socket, it must have the following
@@ -267,6 +275,7 @@ class Transport (threading.Thread, ClosingContextManager):
arguments.
"""
self.active = False
+ self._sshclient = None
if isinstance(sock, string_types):
# convert "host:port" into (host, port)
@@ -279,10 +288,13 @@ class Transport (threading.Thread, ClosingContextManager):
# connect to the given (host, port)
hostname, port = sock
reason = 'No suitable address family'
- for (family, socktype, proto, canonname, sockaddr) in socket.getaddrinfo(hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM):
+ addrinfos = socket.getaddrinfo(
+ hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM
+ )
+ for family, socktype, proto, canonname, sockaddr in addrinfos:
if socktype == socket.SOCK_STREAM:
af = family
- addr = sockaddr
+ # addr = sockaddr
sock = socket.socket(af, socket.SOCK_STREAM)
try:
retry_on_signal(lambda: sock.connect((hostname, port)))
@@ -302,7 +314,7 @@ class Transport (threading.Thread, ClosingContextManager):
# we set the timeout so we can check self.active periodically to
# see if we should bail. socket.timeout exception is never
# propagated.
- self.sock.settimeout(0.1)
+ self.sock.settimeout(self._active_check_timeout)
except AttributeError:
pass
@@ -342,7 +354,8 @@ class Transport (threading.Thread, ClosingContextManager):
self.in_kex = False
self.authenticated = False
self._expected_packet = tuple()
- self.lock = threading.Lock() # synchronization (always higher level than write_lock)
+ # synchronization (always higher level than write_lock)
+ self.lock = threading.Lock()
# tracking open channels
self._channels = ChannelMap()
@@ -363,11 +376,15 @@ class Transport (threading.Thread, ClosingContextManager):
self.logger = util.get_logger(self.log_name)
self.packetizer.set_log(self.logger)
self.auth_handler = None
- self.global_response = None # response Message from an arbitrary global request
- self.completion_event = None # user-defined event callbacks
- self.banner_timeout = 15 # how long (seconds) to wait for the SSH banner
- self.handshake_timeout = 15 # how long (seconds) to wait for the handshake to finish after SSH banner sent.
-
+ # response Message from an arbitrary global request
+ self.global_response = None
+ # user-defined event callbacks
+ self.completion_event = None
+ # how long (seconds) to wait for the SSH banner
+ self.banner_timeout = 15
+ # how long (seconds) to wait for the handshake to finish after SSH
+ # banner sent.
+ self.handshake_timeout = 15
# server mode:
self.server_mode = False
@@ -386,8 +403,10 @@ class Transport (threading.Thread, ClosingContextManager):
out += ' (unconnected)'
else:
if self.local_cipher != '':
- out += ' (cipher %s, %d bits)' % (self.local_cipher,
- self._cipher_info[self.local_cipher]['key-size'] * 8)
+ out += ' (cipher %s, %d bits)' % (
+ self.local_cipher,
+ self._cipher_info[self.local_cipher]['key-size'] * 8
+ )
if self.is_authenticated():
out += ' (active; %d open channel(s))' % len(self._channels)
elif self.initial_kex_done:
@@ -425,7 +444,6 @@ class Transport (threading.Thread, ClosingContextManager):
:param str gss_host: The targets name in the kerberos database
Default: The name of the host to connect to
- :rtype: Void
"""
# We need the FQDN to get this working with SSPI
self.gss_host = socket.getfqdn(gss_host)
@@ -458,8 +476,9 @@ class Transport (threading.Thread, ClosingContextManager):
:param .threading.Event event:
an event to trigger when negotiation is complete (optional)
- :raises SSHException: if negotiation fails (and no ``event`` was passed
- in)
+ :raises:
+ `.SSHException` -- if negotiation fails (and no ``event`` was
+ passed in)
"""
self.active = True
if event is not None:
@@ -492,7 +511,7 @@ class Transport (threading.Thread, ClosingContextManager):
be triggered. On failure, `is_active` will return ``False``.
(Since 1.4) If ``event`` is ``None``, this method will not return until
- negotation is done. On success, the method returns normally.
+ negotiation is done. On success, the method returns normally.
Otherwise an SSHException is raised.
After a successful negotiation, the client will need to authenticate.
@@ -519,8 +538,9 @@ class Transport (threading.Thread, ClosingContextManager):
an object used to perform authentication and create `channels
<.Channel>`
- :raises SSHException: if negotiation fails (and no ``event`` was passed
- in)
+ :raises:
+ `.SSHException` -- if negotiation fails (and no ``event`` was
+ passed in)
"""
if server is None:
server = ServerInterface()
@@ -622,6 +642,9 @@ class Transport (threading.Thread, ClosingContextManager):
Transport._modulus_pack = None
return False
+ def set_sshclient(self, sshclient):
+ self._sshclient = sshclient
+
def close(self):
"""
Close this session, and any open channels that are tied to it.
@@ -632,6 +655,7 @@ class Transport (threading.Thread, ClosingContextManager):
for chan in list(self._channels.values()):
chan._unlink()
self.sock.close()
+ self._sshclient = None
def get_remote_server_key(self):
"""
@@ -642,7 +666,7 @@ class Transport (threading.Thread, ClosingContextManager):
string)``. You can get the same effect by calling `.PKey.get_name`
for the key type, and ``str(key)`` for the key string.
- :raises SSHException: if no session is currently active.
+ :raises: `.SSHException` -- if no session is currently active.
:return: public key (`.PKey`) of the remote server
"""
@@ -660,7 +684,12 @@ class Transport (threading.Thread, ClosingContextManager):
"""
return self.active
- def open_session(self, window_size=None, max_packet_size=None, timeout=None):
+ def open_session(
+ self,
+ window_size=None,
+ max_packet_size=None,
+ timeout=None,
+ ):
"""
Request a new channel to the server, of type ``"session"``. This is
just an alias for calling `open_channel` with an argument of
@@ -677,9 +706,12 @@ class Transport (threading.Thread, ClosingContextManager):
:return: a new `.Channel`
- :raises SSHException: if the request is rejected or the session ends
+ :raises:
+ `.SSHException` -- if the request is rejected or the session ends
prematurely
+ .. versionchanged:: 1.13.4/1.14.3/1.15.3
+ Added the ``timeout`` argument.
.. versionchanged:: 1.15
Added the ``window_size`` and ``max_packet_size`` arguments.
"""
@@ -698,7 +730,8 @@ class Transport (threading.Thread, ClosingContextManager):
x11 port, ie. 6010)
:return: a new `.Channel`
- :raises SSHException: if the request is rejected or the session ends
+ :raises:
+ `.SSHException` -- if the request is rejected or the session ends
prematurely
"""
return self.open_channel('x11', src_addr=src_addr)
@@ -712,14 +745,15 @@ class Transport (threading.Thread, ClosingContextManager):
:return: a new `.Channel`
- :raises SSHException:
+ :raises: `.SSHException` --
if the request is rejected or the session ends prematurely
"""
return self.open_channel('auth-agent@openssh.com')
def open_forwarded_tcpip_channel(self, src_addr, dest_addr):
"""
- Request a new channel back to the client, of type ``"forwarded-tcpip"``.
+ 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.
@@ -763,7 +797,8 @@ class Transport (threading.Thread, ClosingContextManager):
:return: a new `.Channel` on success
- :raises SSHException: if the request is rejected, the session ends
+ :raises:
+ `.SSHException` -- if the request is rejected, the session ends
prematurely or there is a timeout openning a channel
.. versionchanged:: 1.15
@@ -828,7 +863,11 @@ class Transport (threading.Thread, ClosingContextManager):
If a handler is given, that handler is called from a different thread
whenever a forwarded connection arrives. The handler parameters are::
- handler(channel, (origin_addr, origin_port), (server_addr, server_port))
+ handler(
+ channel,
+ (origin_addr, origin_port),
+ (server_addr, server_port),
+ )
where ``server_addr`` and ``server_port`` are the address and port that
the server was listening on.
@@ -846,20 +885,23 @@ class Transport (threading.Thread, ClosingContextManager):
:return: the port number (`int`) allocated by the server
- :raises SSHException: if the server refused the TCP forward request
+ :raises:
+ `.SSHException` -- if the server refused the TCP forward request
"""
if not self.active:
raise SSHException('SSH session not active')
port = int(port)
- response = self.global_request('tcpip-forward', (address, port), wait=True)
+ response = self.global_request(
+ 'tcpip-forward', (address, port), wait=True
+ )
if response is None:
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
+ # 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
@@ -918,8 +960,9 @@ class Transport (threading.Thread, ClosingContextManager):
traffic both ways as the two sides swap keys and do computations. This
method returns when the session has switched to new keys.
- :raises SSHException: if the key renegotiation failed (which causes the
- session to end)
+ :raises:
+ `.SSHException` -- if the key renegotiation failed (which causes
+ the session to end)
"""
self.completion_event = threading.Event()
self._send_kex_init()
@@ -945,8 +988,9 @@ class Transport (threading.Thread, ClosingContextManager):
seconds to wait before sending a keepalive packet (or
0 to disable keepalives).
"""
- self.packetizer.set_keepalive(interval,
- lambda x=weakref.proxy(self): x.global_request('keepalive@lag.net', wait=False))
+ def _request(x=weakref.proxy(self)):
+ return x.global_request('keepalive@lag.net', wait=False)
+ self.packetizer.set_keepalive(interval, _request)
def global_request(self, kind, data=None, wait=True):
"""
@@ -988,8 +1032,8 @@ class Transport (threading.Thread, ClosingContextManager):
def accept(self, timeout=None):
"""
Return the next channel opened by the client over this transport, in
- server mode. If no channel is opened before the given timeout, ``None``
- is returned.
+ server mode. If no channel is opened before the given timeout,
+ ``None`` is returned.
:param int timeout:
seconds to wait for a channel, or ``None`` to wait forever
@@ -1010,8 +1054,17 @@ class Transport (threading.Thread, ClosingContextManager):
self.lock.release()
return chan
- def connect(self, hostkey=None, username='', password=None, pkey=None,
- gss_host=None, gss_auth=False, gss_kex=False, gss_deleg_creds=True):
+ def connect(
+ self,
+ hostkey=None,
+ username='',
+ password=None,
+ pkey=None,
+ gss_host=None,
+ gss_auth=False,
+ gss_kex=False,
+ gss_deleg_creds=True,
+ ):
"""
Negotiate an SSH2 session, and optionally verify the server's host key
and authenticate using a password or private key. This is a shortcut
@@ -1050,7 +1103,7 @@ class Transport (threading.Thread, ClosingContextManager):
:param bool gss_deleg_creds:
Whether to delegate GSS-API client credentials.
- :raises SSHException: if the SSH2 negotiation fails, the host key
+ :raises: `.SSHException` -- if the SSH2 negotiation fails, the host key
supplied by the server is incorrect, or authentication fails.
"""
if hostkey is not None:
@@ -1063,16 +1116,23 @@ class Transport (threading.Thread, ClosingContextManager):
# the host key.
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()):
+ 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(hostkey.asbytes())))
- self._log(DEBUG, 'Got : %s: %s' % (key.get_name(), repr(key.asbytes())))
+ 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())
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)')
+ 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)')
@@ -1117,7 +1177,7 @@ class Transport (threading.Thread, ClosingContextManager):
passed to the `.SubsystemHandler` constructor later.
:param str name: name of the subsystem.
- :param class handler:
+ :param handler:
subclass of `.SubsystemHandler` that handles this subsystem.
"""
try:
@@ -1135,7 +1195,11 @@ class Transport (threading.Thread, ClosingContextManager):
successfully; False if authentication failed and/or the session is
closed.
"""
- return self.active and (self.auth_handler is not None) and self.auth_handler.is_authenticated()
+ return (
+ self.active and
+ self.auth_handler is not None and
+ self.auth_handler.is_authenticated()
+ )
def get_username(self):
"""
@@ -1174,9 +1238,11 @@ class Transport (threading.Thread, ClosingContextManager):
`list` of auth types permissible for the next stage of
authentication (normally empty)
- :raises BadAuthenticationType: if "none" authentication isn't allowed
+ :raises:
+ `.BadAuthenticationType` -- if "none" authentication isn't allowed
by the server for this user
- :raises SSHException: if the authentication failed due to a network
+ :raises:
+ `.SSHException` -- if the authentication failed due to a network
error
.. versionadded:: 1.5
@@ -1227,14 +1293,17 @@ class Transport (threading.Thread, ClosingContextManager):
`list` of auth types permissible for the next stage of
authentication (normally empty)
- :raises BadAuthenticationType: if password authentication isn't
+ :raises:
+ `.BadAuthenticationType` -- if password authentication isn't
allowed by the server for this user (and no event was passed in)
- :raises AuthenticationException: if the authentication failed (and no
+ :raises:
+ `.AuthenticationException` -- if the authentication failed (and no
event was passed in)
- :raises SSHException: if there was a network error
+ :raises: `.SSHException` -- if there was a network error
"""
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
+ # we should never try to send the password unless we're on a secure
+ # link
raise SSHException('No existing session')
if event is None:
my_event = threading.Event()
@@ -1248,7 +1317,8 @@ class Transport (threading.Thread, ClosingContextManager):
try:
return self.auth_handler.wait_for_response(my_event)
except BadAuthenticationType as e:
- # if password auth isn't allowed, but keyboard-interactive *is*, try to fudge it
+ # 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):
raise
try:
@@ -1294,11 +1364,13 @@ class Transport (threading.Thread, ClosingContextManager):
`list` of auth types permissible for the next stage of
authentication (normally empty)
- :raises BadAuthenticationType: if public-key authentication isn't
+ :raises:
+ `.BadAuthenticationType` -- if public-key authentication isn't
allowed by the server for this user (and no event was passed in)
- :raises AuthenticationException: if the authentication failed (and no
+ :raises:
+ `.AuthenticationException` -- if the authentication failed (and no
event was passed in)
- :raises SSHException: if there was a network error
+ :raises: `.SSHException` -- if there was a network error
"""
if (not self.active) or (not self.initial_kex_done):
# we should never try to authenticate unless we're on a secure link
@@ -1350,10 +1422,10 @@ class Transport (threading.Thread, ClosingContextManager):
`list` of auth types permissible for the next stage of
authentication (normally empty).
- :raises BadAuthenticationType: if public-key authentication isn't
+ :raises: `.BadAuthenticationType` -- if public-key authentication isn't
allowed by the server for this user
- :raises AuthenticationException: if the authentication failed
- :raises SSHException: if there was a network error
+ :raises: `.AuthenticationException` -- if the authentication failed
+ :raises: `.SSHException` -- if there was a network error
.. versionadded:: 1.5
"""
@@ -1362,7 +1434,9 @@ class Transport (threading.Thread, ClosingContextManager):
raise SSHException('No existing session')
my_event = threading.Event()
self.auth_handler = AuthHandler(self)
- self.auth_handler.auth_interactive(username, handler, my_event, submethods)
+ self.auth_handler.auth_interactive(
+ username, handler, my_event, submethods
+ )
return self.auth_handler.wait_for_response(my_event)
def auth_interactive_dumb(self, username, handler=None, submethods=''):
@@ -1380,8 +1454,8 @@ class Transport (threading.Thread, ClosingContextManager):
print(title.strip())
if instructions:
print(instructions.strip())
- for prompt,show_input in prompt_list:
- print(prompt.strip(),end=' ')
+ for prompt, show_input in prompt_list:
+ print(prompt.strip(), end=' ')
answers.append(input())
return answers
return self.auth_interactive(username, handler, submethods)
@@ -1396,36 +1470,37 @@ class Transport (threading.Thread, ClosingContextManager):
:return: list of auth types permissible for the next stage of
authentication (normally empty)
:rtype: list
- :raise BadAuthenticationType: if gssapi-with-mic isn't
+ :raises: `.BadAuthenticationType` -- if gssapi-with-mic isn't
allowed by the server (and no event was passed in)
- :raise AuthenticationException: if the authentication failed (and no
+ :raises:
+ `.AuthenticationException` -- if the authentication failed (and no
event was passed in)
- :raise SSHException: if there was a network error
+ :raises: `.SSHException` -- if there was a network error
"""
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')
my_event = threading.Event()
self.auth_handler = AuthHandler(self)
- self.auth_handler.auth_gssapi_with_mic(username, gss_host, gss_deleg_creds, my_event)
+ self.auth_handler.auth_gssapi_with_mic(
+ username, gss_host, gss_deleg_creds, my_event
+ )
return self.auth_handler.wait_for_response(my_event)
def auth_gssapi_keyex(self, username):
"""
- Authenticate to the Server with GSS-API / SSPI if GSS-API Key Exchange
- was the used key exchange method.
+ Authenticate to the server with GSS-API/SSPI if GSS-API kex is in use.
- :param str username: The username to authenticate as
- :param str gss_host: The target host
- :param bool gss_deleg_creds: Delegate credentials or not
- :return: list of auth types permissible for the next stage of
- authentication (normally empty)
- :rtype: list
- :raise BadAuthenticationType: if GSS-API Key Exchange was not performed
- (and no event was passed in)
- :raise AuthenticationException: if the authentication failed (and no
- event was passed in)
- :raise SSHException: if there was a network error
+ :param str username: The username to authenticate as.
+ :returns:
+ a `list` of auth types permissible for the next stage of
+ authentication (normally empty)
+ :raises: `.BadAuthenticationType` --
+ if GSS-API Key Exchange was not performed (and no event was passed
+ in)
+ :raises: `.AuthenticationException` --
+ if the authentication failed (and no event was passed in)
+ :raises: `.SSHException` -- if there was a network error
"""
if (not self.active) or (not self.initial_kex_done):
# we should never try to authenticate unless we're on a secure link
@@ -1503,9 +1578,10 @@ class Transport (threading.Thread, ClosingContextManager):
def getpeername(self):
"""
Return the address of the remote side of this Transport, if possible.
- This is effectively a wrapper around ``'getpeername'`` on the underlying
- socket. If the socket-like object has no ``'getpeername'`` method,
- then ``("unknown", 0)`` is returned.
+
+ This is effectively a wrapper around ``getpeername`` on the underlying
+ socket. If the socket-like object has no ``getpeername`` method, then
+ ``("unknown", 0)`` is returned.
:return:
the address of the remote host, if known, as a ``(str, int)``
@@ -1519,10 +1595,27 @@ class Transport (threading.Thread, ClosingContextManager):
def stop_thread(self):
self.active = False
self.packetizer.close()
- while self.is_alive() and (self is not threading.current_thread()):
- self.join(10)
-
- ### internals...
+ if PY2:
+ # Original join logic; #520 doesn't appear commonly present under
+ # Python 2.
+ while self.is_alive() and self is not threading.current_thread():
+ self.join(10)
+ else:
+ # Keep trying to join() our main thread, quickly, until:
+ # * We join()ed successfully (self.is_alive() == False)
+ # * Or it looks like we've hit issue #520 (socket.recv hitting some
+ # race condition preventing it from timing out correctly), wherein
+ # 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.join(0.1)
+
+ # internals...
def _log(self, level, msg, *args):
if issubclass(type(msg), list):
@@ -1560,28 +1653,32 @@ 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.')
+ 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')
+ raise SSHException('Key-exchange timed out waiting for key negotiation') # noqa
try:
self._send_message(data)
finally:
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 obj to set the K (root key) and H (exchange hash).
+ """
self.K = k
self.H = h
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 obj to register the next packet type it expects to see.
+ """
self._expected_packet = tuple(ptypes)
def _verify_key(self, host_key, sig):
@@ -1589,7 +1686,7 @@ class Transport (threading.Thread, ClosingContextManager):
if key is None:
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)
+ raise SSHException('Signature verification (%s) failed.' % self.host_key_type) # noqa
self.host_key = key
def _compute_key(self, id, nbytes):
@@ -1602,7 +1699,9 @@ class Transport (threading.Thread, ClosingContextManager):
# 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_select_msg = "kex engine %s specified hash_algo %r" % (self.kex_engine.__class__.__name__, hash_algo)
+ hash_select_msg = "kex engine %s specified hash_algo %r" % (
+ self.kex_engine.__class__.__name__, hash_algo
+ )
if hash_algo is None:
hash_algo = sha1
hash_select_msg += ", falling back to sha1"
@@ -1683,14 +1782,15 @@ class Transport (threading.Thread, ClosingContextManager):
# active=True occurs before the thread is launched, to avoid a race
_active_threads.append(self)
+ tid = hex(long(id(self)) & xffffffff)
if self.server_mode:
- self._log(DEBUG, 'starting thread (server mode): %s' % hex(long(id(self)) & xffffffff))
+ self._log(DEBUG, 'starting thread (server mode): %s' % tid)
else:
- self._log(DEBUG, 'starting thread (client mode): %s' % hex(long(id(self)) & xffffffff))
+ 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)
+ 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
@@ -1722,7 +1822,7 @@ 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))
+ 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)
@@ -1736,13 +1836,17 @@ 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)
+ self._log(DEBUG, 'Ignoring message for dead channel %d' % chanid) # noqa
else:
- self._log(ERROR, 'Channel request for unknown channel %d' % chanid)
+ 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._handler_table[ptype](self.auth_handler, m)
+ elif (
+ 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)
else:
self._log(WARNING, 'Oops, unhandled type %d' % ptype)
msg = Message()
@@ -1756,7 +1860,6 @@ class Transport (threading.Thread, ClosingContextManager):
self.saved_exception = 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 as e:
if type(e.args) is tuple:
@@ -1810,7 +1913,7 @@ class Transport (threading.Thread, ClosingContextManager):
msg += "local={0}, remote={1}".format(local, remote)
self._log(DEBUG, msg)
- ### protocol stages
+ # protocol stages
def _negotiate_keys(self, m):
# throws SSHException on anything unusual
@@ -1839,7 +1942,9 @@ class Transport (threading.Thread, ClosingContextManager):
except ProxyCommandFailure:
raise
except Exception as e:
- raise SSHException('Error reading SSH protocol banner' + str(e))
+ raise SSHException(
+ 'Error reading SSH protocol banner' + str(e)
+ )
if buf[:4] == 'SSH-':
break
self._log(DEBUG, 'Banner: ' + buf)
@@ -1849,10 +1954,10 @@ class Transport (threading.Thread, ClosingContextManager):
self.remote_version = buf
self._log(DEBUG, 'Remote version/idstring: %s' % buf)
# pull off any attached comment
- comment = ''
+ # NOTE: comment used to be stored in a variable and then...never used.
+ # since 2003. ca 877cd974b8182d26fa76d566072917ea67b64e67
i = buf.find(' ')
if i >= 0:
- comment = buf[i+1:]
buf = buf[:i]
# parse out version string and make sure it matches
segs = buf.split('-', 2)
@@ -1861,8 +1966,10 @@ class Transport (threading.Thread, ClosingContextManager):
version = segs[1]
client = segs[2]
if version != '1.99' and version != '2.0':
- raise SSHException('Incompatible version (%s instead of 2.0)' % (version,))
- self._log(INFO, 'Connected (version %s, client %s)' % (version, client))
+ msg = 'Incompatible version ({0} instead of 2.0)'
+ raise SSHException(msg.format(version))
+ msg = 'Connected (version {0}, client {1})'.format(version, client)
+ self._log(INFO, msg)
def _send_kex_init(self):
"""
@@ -1877,14 +1984,24 @@ class Transport (threading.Thread, ClosingContextManager):
self.in_kex = True
if self.server_mode:
mp_required_prefix = 'diffie-hellman-group-exchange-sha'
- kex_mp = [k for k in self._preferred_kex if k.startswith(mp_required_prefix)]
+ kex_mp = [
+ 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
- if not k.startswith(mp_required_prefix)]
+ # 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
+ 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
@@ -1908,7 +2025,7 @@ class Transport (threading.Thread, ClosingContextManager):
self._send_message(m)
def _parse_kex_init(self, m):
- cookie = m.get_bytes(16)
+ 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()
@@ -1920,18 +2037,21 @@ class Transport (threading.Thread, ClosingContextManager):
client_lang_list = m.get_list()
server_lang_list = m.get_list()
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) +
- ' 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
# support.
@@ -1948,34 +2068,48 @@ class Transport (threading.Thread, ClosingContextManager):
self._preferred_kex
))
if len(agreed_kex) == 0:
- raise SSHException('Incompatible ssh peer (no acceptable kex algorithm)')
+ 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)')
+ 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)')
+ raise SSHException('Incompatible ssh peer (can\'t match requested host key type)') # noqa
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))
- if (len(agreed_local_ciphers) == 0) or (len(agreed_remote_ciphers) == 0):
- raise SSHException('Incompatible ssh server (no acceptable 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
self.local_cipher = agreed_local_ciphers[0]
self.remote_cipher = agreed_remote_ciphers[0]
self._log_agreement(
@@ -1983,11 +2117,19 @@ class Transport (threading.Thread, ClosingContextManager):
)
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)')
self.local_mac = agreed_local_macs[0]
@@ -1997,13 +2139,32 @@ class Transport (threading.Thread, ClosingContextManager):
)
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))
- 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))
+ 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
+ ):
+ 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(
@@ -2020,15 +2181,22 @@ class Transport (threading.Thread, ClosingContextManager):
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)
- key_in = self._compute_key('C', self._cipher_info[self.remote_cipher]['key-size'])
+ key_in = self._compute_key(
+ 'C', self._cipher_info[self.remote_cipher]['key-size']
+ )
else:
IV_in = self._compute_key('B', block_size)
- key_in = self._compute_key('D', self._cipher_info[self.remote_cipher]['key-size'])
- engine = self._get_cipher(self.remote_cipher, key_in, IV_in, self._DECRYPT)
+ key_in = self._compute_key(
+ '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']
# initial mac keys are done in the hash's natural size (not the
@@ -2037,25 +2205,37 @@ class Transport (threading.Thread, ClosingContextManager):
mac_key = self._compute_key('E', mac_engine().digest_size)
else:
mac_key = self._compute_key('F', mac_engine().digest_size)
- self.packetizer.set_inbound_cipher(engine, block_size, mac_engine, mac_size, mac_key)
+ 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.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(cMSG_NEWKEYS)
self._send_message(m)
block_size = self._cipher_info[self.local_cipher]['block-size']
if self.server_mode:
IV_out = self._compute_key('B', block_size)
- key_out = self._compute_key('D', self._cipher_info[self.local_cipher]['key-size'])
+ key_out = self._compute_key(
+ 'D', self._cipher_info[self.local_cipher]['key-size'])
else:
IV_out = self._compute_key('A', block_size)
- key_out = self._compute_key('C', self._cipher_info[self.local_cipher]['key-size'])
- engine = self._get_cipher(self.local_cipher, key_out, IV_out, self._ENCRYPT)
+ key_out = self._compute_key(
+ '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']
# initial mac keys are done in the hash's natural size (not the
@@ -2065,9 +2245,16 @@ class Transport (threading.Thread, ClosingContextManager):
else:
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)
+ self.packetizer.set_outbound_cipher(
+ 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.packetizer.set_outbound_compressor(compress_out())
if not self.packetizer.need_rekey():
@@ -2123,7 +2310,10 @@ class Transport (threading.Thread, ClosingContextManager):
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)
+ self._log(
+ DEBUG,
+ 'Rejecting "%s" global request from server.' % kind
+ )
ok = False
elif kind == 'tcpip-forward':
address = m.get_text()
@@ -2174,7 +2364,8 @@ class Transport (threading.Thread, ClosingContextManager):
return
self.lock.acquire()
try:
- chan._set_remote_channel(server_chanid, server_window_size, server_max_packet_size)
+ chan._set_remote_channel(
+ 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()
@@ -2187,9 +2378,13 @@ class Transport (threading.Thread, ClosingContextManager):
chanid = m.get_int()
reason = m.get_int()
reason_str = m.get_text()
- lang = m.get_text()
+ m.get_text() # ignored language
reason_text = CONNECTION_FAILED_CODE.get(reason, '(unknown code)')
- self._log(ERROR, 'Secsh channel %d open FAILED: %s: %s' % (chanid, reason_str, reason_text))
+ self._log(
+ ERROR,
+ 'Secsh channel %d open FAILED: %s: %s' % (
+ chanid, reason_str, reason_text)
+ )
self.lock.acquire()
try:
self.saved_exception = ChannelException(reason, reason_text)
@@ -2208,7 +2403,10 @@ class Transport (threading.Thread, ClosingContextManager):
initial_window_size = m.get_int()
max_packet_size = m.get_int()
reject = False
- if (kind == 'auth-agent@openssh.com') and (self._forward_agent_handler is not None):
+ if (
+ kind == 'auth-agent@openssh.com' and
+ self._forward_agent_handler is not None
+ ):
self._log(DEBUG, 'Incoming forward agent connection')
self.lock.acquire()
try:
@@ -2218,7 +2416,11 @@ class Transport (threading.Thread, ClosingContextManager):
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))
+ self._log(
+ DEBUG,
+ 'Incoming x11 connection from %s:%d' % (
+ origin_addr, origin_port)
+ )
self.lock.acquire()
try:
my_chanid = self._next_channel()
@@ -2229,14 +2431,20 @@ class Transport (threading.Thread, ClosingContextManager):
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))
+ self._log(
+ DEBUG,
+ 'Incoming tcp forwarded connection from %s:%d' % (
+ origin_addr, origin_port)
+ )
self.lock.acquire()
try:
my_chanid = self._next_channel()
finally:
self.lock.release()
elif not self.server_mode:
- self._log(DEBUG, 'Rejecting "%s" channel request from server.' % kind)
+ self._log(
+ DEBUG,
+ 'Rejecting "%s" channel request from server.' % kind)
reject = True
reason = OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED
else:
@@ -2246,17 +2454,23 @@ class Transport (threading.Thread, ClosingContextManager):
finally:
self.lock.release()
if kind == 'direct-tcpip':
- # handle direct-tcpip requests comming from the client
+ # handle direct-tcpip requests coming from the client
dest_addr = m.get_text()
dest_port = m.get_int()
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)
+ reason = self.server_object.check_channel_request(
+ kind, my_chanid)
if reason != OPEN_SUCCEEDED:
- self._log(DEBUG, 'Rejecting "%s" channel request from client.' % kind)
+ self._log(
+ DEBUG,
+ 'Rejecting "%s" channel request from client.' % kind)
reject = True
if reject:
msg = Message()
@@ -2274,8 +2488,10 @@ class Transport (threading.Thread, ClosingContextManager):
self._channels.put(my_chanid, chan)
self.channels_seen[my_chanid] = True
chan._set_transport(self)
- chan._set_window(self.default_window_size, self.default_max_packet_size)
- chan._set_remote_channel(chanid, initial_window_size, max_packet_size)
+ chan._set_window(
+ self.default_window_size, self.default_max_packet_size)
+ chan._set_remote_channel(
+ chanid, initial_window_size, max_packet_size)
finally:
self.lock.release()
m = Message()
@@ -2292,14 +2508,18 @@ class Transport (threading.Thread, ClosingContextManager):
self._x11_handler(chan, (origin_addr, origin_port))
elif kind == 'forwarded-tcpip':
chan.origin_addr = (origin_addr, origin_port)
- self._tcp_handler(chan, (origin_addr, origin_port), (server_addr, server_port))
+ self._tcp_handler(
+ chan,
+ (origin_addr, origin_port),
+ (server_addr, server_port)
+ )
else:
self._queue_incoming_channel(chan)
def _parse_debug(self, m):
- always_display = m.get_boolean()
+ m.get_boolean() # always_display
msg = m.get_string()
- lang = m.get_string()
+ m.get_string() # language
self._log(DEBUG, 'Debug msg: {0}'.format(util.safe_string(msg)))
def _get_subsystem_handler(self, name):
@@ -2346,7 +2566,6 @@ 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__ = '_transport'
def __init__(self, transport):