diff options
Diffstat (limited to 'paramiko/transport.py')
-rw-r--r-- | paramiko/transport.py | 70 |
1 files changed, 58 insertions, 12 deletions
diff --git a/paramiko/transport.py b/paramiko/transport.py index 9517d4a9..22348f87 100644 --- a/paramiko/transport.py +++ b/paramiko/transport.py @@ -247,11 +247,17 @@ class Transport(threading.Thread, ClosingContextManager): _key_info = { "ssh-rsa": RSAKey, + "ssh-rsa-cert-v01@openssh.com": RSAKey, "ssh-dss": DSSKey, + "ssh-dss-cert-v01@openssh.com": DSSKey, "ecdsa-sha2-nistp256": ECDSAKey, + "ecdsa-sha2-nistp256-cert-v01@openssh.com": ECDSAKey, "ecdsa-sha2-nistp384": ECDSAKey, + "ecdsa-sha2-nistp384-cert-v01@openssh.com": ECDSAKey, "ecdsa-sha2-nistp521": ECDSAKey, + "ecdsa-sha2-nistp521-cert-v01@openssh.com": ECDSAKey, "ssh-ed25519": Ed25519Key, + "ssh-ed25519-cert-v01@openssh.com": Ed25519Key, } _kex_info = { @@ -332,10 +338,12 @@ class Transport(threading.Thread, ClosingContextManager): arguments. """ self.active = False + self.hostname = None if isinstance(sock, string_types): # convert "host:port" into (host, port) hl = sock.split(":", 1) + self.hostname = hl[0] if len(hl) == 1: sock = (hl[0], 22) else: @@ -343,6 +351,7 @@ class Transport(threading.Thread, ClosingContextManager): if type(sock) is tuple: # connect to the given (host, port) hostname, port = sock + self.hostname = hostname reason = "No suitable address family" addrinfos = socket.getaddrinfo( hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM @@ -487,15 +496,39 @@ class Transport(threading.Thread, ClosingContextManager): """ return SecurityOptions(self) - def set_gss_host(self, gss_host): + def set_gss_host(self, gss_host, trust_dns=True, gssapi_requested=True): """ - Setter for C{gss_host} if GSS-API Key Exchange is performed. + Normalize/canonicalize ``self.gss_host`` depending on various factors. - :param str gss_host: The targets name in the kerberos database - Default: The name of the host to connect to - """ - # We need the FQDN to get this working with SSPI - self.gss_host = socket.getfqdn(gss_host) + :param str gss_host: + The explicitly requested GSS-oriented hostname to connect to (i.e. + what the host's name is in the Kerberos database.) Defaults to + ``self.hostname`` (which will be the 'real' target hostname and/or + host portion of given socket object.) + :param bool trust_dns: + Indicates whether or not DNS is trusted; if true, DNS will be used + to canonicalize the GSS hostname (which again will either be + ``gss_host`` or the transport's default hostname.) + (Defaults to True due to backwards compatibility.) + :param bool gssapi_requested: + Whether GSSAPI key exchange or authentication was even requested. + If not, this is a no-op and nothing happens + (and ``self.gss_host`` is not set.) + (Defaults to True due to backwards compatibility.) + :returns: ``None``. + """ + # No GSSAPI in play == nothing to do + if not gssapi_requested: + return + # Obtain the correct host first - did user request a GSS-specific name + # to use that is distinct from the actual SSH target hostname? + if gss_host is None: + gss_host = self.hostname + # Finally, canonicalize via DNS if DNS is trusted. + if trust_dns and gss_host is not None: + gss_host = socket.getfqdn(gss_host) + # And set attribute for reference later. + self.gss_host = gss_host def start_client(self, event=None, timeout=None): """ @@ -1120,6 +1153,7 @@ class Transport(threading.Thread, ClosingContextManager): gss_auth=False, gss_kex=False, gss_deleg_creds=True, + gss_trust_dns=True, ): """ Negotiate an SSH2 session, and optionally verify the server's host key @@ -1158,13 +1192,26 @@ class Transport(threading.Thread, ClosingContextManager): Perform GSS-API Key Exchange and user authentication. :param bool gss_deleg_creds: Whether to delegate GSS-API client credentials. + :param gss_trust_dns: + Indicates whether or not the DNS is trusted to securely + canonicalize the name of the host being connected to (default + ``True``). :raises: `.SSHException` -- if the SSH2 negotiation fails, the host key supplied by the server is incorrect, or authentication fails. + + .. versionchanged:: 2.3 + Added the ``gss_trust_dns`` argument. """ if hostkey is not None: self._preferred_keys = [hostkey.get_name()] + self.set_gss_host( + gss_host=gss_host, + trust_dns=gss_trust_dns, + gssapi_requested=gss_kex or gss_auth, + ) + self.start_client() # check host key if we were given one @@ -1194,7 +1241,9 @@ class Transport(threading.Thread, ClosingContextManager): self._log( DEBUG, "Attempting GSS-API auth... (gssapi-with-mic)" ) # noqa - self.auth_gssapi_with_mic(username, gss_host, gss_deleg_creds) + self.auth_gssapi_with_mic( + username, self.gss_host, gss_deleg_creds + ) elif gss_kex: self._log(DEBUG, "Attempting GSS-API auth... (gssapi-keyex)") self.auth_gssapi_keyex(username) @@ -1928,8 +1977,6 @@ class Transport(threading.Thread, ClosingContextManager): continue elif ptype == MSG_DISCONNECT: self._parse_disconnect(m) - self.active = False - self.packetizer.close() break elif ptype == MSG_DEBUG: self._parse_debug(m) @@ -1968,8 +2015,7 @@ class Transport(threading.Thread, ClosingContextManager): "Channel request for unknown channel %d" % chanid, ) # noqa - self.active = False - self.packetizer.close() + break elif ( self.auth_handler is not None and ptype in self.auth_handler._handler_table |