summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--demos/demo_simple.py2
-rw-r--r--paramiko/client.py20
-rw-r--r--paramiko/transport.py25
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)