diff options
author | Anselm Kruis <a.kruis@science-computing.de> | 2017-08-05 14:24:10 +0200 |
---|---|---|
committer | sdeiss@science-computing.de <sdeiss@science-computing.de> | 2017-09-13 14:53:27 +0200 |
commit | ad5c0d17fffd6b365a5477d2b884d3207879d8b8 (patch) | |
tree | 359c500d90290179a9ce233a882d8feac9580ccb | |
parent | c4aed573db0392ec35f1dbe3d4ba6aa0b25f8815 (diff) |
Invent the parameter 'gss_trust_dns' for Kerberos support
In response to Paramiko issue #915 the parameter 'gss_trust_dns' was
added for Kerberos support. Set by default to 'True' the parameter
indicates whether or not the DNS is trusted to securely canonicalize
the hostname of the target host. If set to 'False' the hostname
entered will be passed to GSSAPI.
This option behaves like GSSAPITrustDNS from OpenSSH.
Also, the parameter 'gss_host' is now always set, regardless if GSSAPI
is used or not.
Further, a minor fix was required to make the SFTP test work again.
-rw-r--r-- | demos/demo_simple.py | 2 | ||||
-rw-r--r-- | paramiko/client.py | 20 | ||||
-rw-r--r-- | paramiko/transport.py | 25 |
3 files changed, 32 insertions, 15 deletions
diff --git a/demos/demo_simple.py b/demos/demo_simple.py index 7ae3d8c8..9def57f8 100644 --- a/demos/demo_simple.py +++ b/demos/demo_simple.py @@ -79,8 +79,6 @@ try: if not UseGSSAPI and not DoGSSAPIKeyExchange: client.connect(hostname, port, username, password) else: - # SSPI works only with the FQDN of the target host - hostname = socket.getfqdn(hostname) try: client.connect(hostname, port, username, gss_auth=UseGSSAPI, gss_kex=DoGSSAPIKeyExchange) diff --git a/paramiko/client.py b/paramiko/client.py index 34491230..a9677b05 100644 --- a/paramiko/client.py +++ b/paramiko/client.py @@ -228,6 +228,7 @@ class SSHClient (ClosingContextManager): gss_host=None, banner_timeout=None, auth_timeout=None, + gss_trust_dns=True ): """ Connect to an SSH server and authenticate to it. The server's host key @@ -277,6 +278,9 @@ class SSHClient (ClosingContextManager): :param bool gss_deleg_creds: Delegate GSS-API client credentials or not :param str gss_host: The targets name in the kerberos database. default: hostname + :param bool gss_trust_dns: Indicates whether or not the DNS is trusted to + securely canonicalize the name of the host being + connected to (default ``True``). :param float banner_timeout: an optional timeout (in seconds) to wait for the SSH banner to be presented. :param float auth_timeout: an optional timeout (in seconds) to wait for @@ -331,12 +335,11 @@ class SSHClient (ClosingContextManager): t = self._transport = Transport( sock, gss_kex=gss_kex, gss_deleg_creds=gss_deleg_creds) t.use_compression(compress=compress) - if gss_kex and gss_host is None: - t.set_gss_host(hostname) - elif gss_kex and gss_host is not None: - t.set_gss_host(gss_host) - else: - pass + if gss_host is None: + t.set_gss_host(hostname, gss_trust_dns) + elif gss_host is not None: + # Don't canonicalize gss_host + t.set_gss_host(gss_host, False) if self._log_channel is not None: t.set_log_channel(self._log_channel) if banner_timeout is not None: @@ -387,10 +390,9 @@ class SSHClient (ClosingContextManager): key_filenames = [key_filename] else: key_filenames = key_filename - if gss_host is None: - gss_host = hostname + self._auth(username, password, pkey, key_filenames, allow_agent, - look_for_keys, gss_auth, gss_kex, gss_deleg_creds, gss_host) + look_for_keys, gss_auth, gss_kex, gss_deleg_creds, t.gss_host) def close(self): """ diff --git a/paramiko/transport.py b/paramiko/transport.py index 55c0fa62..8131daa1 100644 --- a/paramiko/transport.py +++ b/paramiko/transport.py @@ -292,10 +292,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: @@ -303,6 +305,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 @@ -446,15 +449,20 @@ class Transport(threading.Thread, ClosingContextManager): """ return SecurityOptions(self) - def set_gss_host(self, gss_host): + def set_gss_host(self, gss_host, dns_lookup=True): """ Setter for C{gss_host} if GSS-API Key Exchange is performed. :param str gss_host: The targets name in the kerberos database Default: The name of the host to connect to + :param bool dns_lookup: Indicates whether or not ``gss_host`` should be + canonicalized (default ``True``). + :rtype: Void """ - # We need the FQDN to get this working with SSPI - self.gss_host = socket.getfqdn(gss_host) + if dns_lookup: + self.gss_host = socket.getfqdn(gss_host) + else: + self.gss_host = gss_host def start_client(self, event=None, timeout=None): """ @@ -1075,6 +1083,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 @@ -1113,6 +1122,9 @@ 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. @@ -1120,6 +1132,11 @@ class Transport(threading.Thread, ClosingContextManager): if hostkey is not None: self._preferred_keys = [hostkey.get_name()] + if gss_host is not None: + self.set_gss_host(gss_host, False) + elif self.hostname is not None: + self.set_gss_host(self.hostname, gss_trust_dns) + self.start_client() # check host key if we were given one @@ -1144,7 +1161,7 @@ class Transport(threading.Thread, ClosingContextManager): 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.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) |