[20089] in Athena Bugs

home help back first fref pref prev next nref lref last post

SSH patch to deal with krb5 to non-reverse-resolving hosts

daemon@ATHENA.MIT.EDU (Derek Atkins)
Tue Jan 8 17:16:46 2002

To: bugs@MIT.EDU
Cc: ghudson@MIT.EDU
From: Derek Atkins <warlord@MIT.EDU>
Date: 08 Jan 2002 17:16:44 -0500
Message-ID: <sjmadvowks3.fsf@indiana.mit.edu>

The following patch to ssh will fix the problem of trying to ssh to a
host that does not have proper reverse resolution.  It will try the
canonical hostname (reverse-resolution of getpeername()) first, and if
that fails it will fallback to the name provided by the user.

I've tested this patch and it appears to work for all the hosts that I
tried (including athena.dialup.mit.edu, fbn.ihtfp.org, and
penguin.ihtfp.org).

-derek

--- sshconnect.c.orig	Tue Mar  9 00:13:20 1999
+++ sshconnect.c	Tue Jan  8 17:07:38 2002
@@ -936,7 +936,7 @@
 }
 
 #ifdef KERBEROS
-int try_kerberos_authentication(void)
+int try_kerberos_authentication(const char *orighost)
 {
 #ifdef KRB5
   char *remotehost;
@@ -950,9 +950,9 @@
   krb5_keyblock   *session_key = 0;
   krb5_ap_rep_enc_part *repl = 0;
   struct sockaddr_in local, foreign;
+  int retry;
   
   memset(&auth, 0 , sizeof(auth));
-  remotehost = (char *) get_canonical_hostname();
   if (!ssh_context)
     {
       if ((r = krb5_init_context(&ssh_context)))
@@ -966,31 +966,88 @@
       goto cleanup;
     }
   
-  memset((char *)&creds, 0, sizeof(creds));
-  if ((r = krb5_sname_to_principal(ssh_context, remotehost,
-				   "host", KRB5_NT_SRV_HST,
-				   &creds.server)))
-    {
-      debug("Kerberos V5: error while constructing service name: %.100s.",
-	    error_message(r));
-      goto cleanup;
-    }
-  if ((r = krb5_cc_get_principal(ssh_context, ccache,
-				 &creds.client)))
-    {
-      debug("Kerberos V5: failure on principal (%.100s).",
-	    error_message(r));
-      goto cleanup;
-    }
+  /* Obtain the server credentials..  We try two things.  First
+   * we try the canonical host (which is the reverse-resolution
+   * of the ip address obtained from getpeername()).  If that fails
+   * to give us a service ticket, fall back to the name supplied
+   * by the user (orighost).  If _that_ fails, then give up. :)
+   *
+   * Derek Atkins <warlord@MIT.EDU>      2002-01-08
+   */
+  retry = 0;
+  remotehost = (char *) get_canonical_hostname();
+  do {
+    char **hostrealms;
+    memset((char *)&creds, 0, sizeof(creds));
+    if ((r = krb5_get_host_realm (ssh_context, remotehost, &hostrealms)))
+      {
+	debug("Kerberos V5: error while obtaining host realm: %.100s.",
+	      error_message(r));
+	goto cleanup;
+      }
+
+    /* Note, this assumes that hostrealm[0] is valid. */
+    if ((r = krb5_build_principal (ssh_context, &creds.server,
+				   strlen(hostrealms[0]), hostrealms[0],
+				   "host", remotehost, NULL)))
+      {
+	debug("Kerberos V5: error while constructing service name: %.100s.",
+	      error_message(r));
+	krb5_free_host_realm (ssh_context, hostrealms);
+	goto cleanup;
+      }
+
+    krb5_free_host_realm (ssh_context, hostrealms);
+
+    if ((r = krb5_cc_get_principal(ssh_context, ccache, &creds.client)))
+      {
+	debug("Kerberos V5: failure on principal (%.100s).",
+	      error_message(r));
+	goto cleanup;
+      }
   
-  creds.keyblock.enctype=ENCTYPE_DES_CBC_CRC;
-  if ((r = krb5_get_credentials(ssh_context, 0,
-				ccache, &creds, &new_creds)))
-    {
-      debug("Kerberos V5: failure on credentials(%.100s).",
-	    error_message(r));
-      goto cleanup;
-    }
+    creds.keyblock.enctype=ENCTYPE_DES_CBC_CRC;
+    if ((r = krb5_get_credentials(ssh_context, 0,
+				  ccache, &creds, &new_creds)))
+      {
+	char *name;
+	krb5_unparse_name (ssh_context, creds.server, &name);
+	debug("Kerberos V5: failure on credentials for %s (%.100s)."
+	      "\n\t(%s)",
+	      remotehost, error_message(r), name);
+	xfree(name);
+
+	if (retry) {
+	  xfree (remotehost);
+	  goto cleanup;
+	}
+
+	if (orighost) {
+	  struct hostent *hp_static;
+
+#if defined(SOCKS5) && !defined(HAVE_SOCKS_H)
+	  hp_static = Rgethostbyname(orighost);
+#else
+	  hp_static = gethostbyname(orighost);
+#endif
+	  orighost = NULL;
+	  if (hp_static) {
+	    remotehost = xstrdup (hp_static->h_name);
+	    krb5_free_cred_contents(ssh_context, &creds);
+	    retry = 1;
+	    continue;
+	  }
+	}
+	goto cleanup;
+
+      } else {
+	if (retry) {
+	  xfree (remotehost);
+	  retry = 0;
+	}
+      }
+
+  } while (retry);
   
   /* ap_opts = AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY; */
   ap_opts = 0;
@@ -1666,7 +1723,7 @@
     {
       debug("Trying Kerberos V5 authentication.");
 #endif
-      if (try_kerberos_authentication()) {
+      if (try_kerberos_authentication(orighost)) {
         /* The server should respond with success or failure. */
         type = packet_read();
         if (type == SSH_SMSG_SUCCESS)


-- 
       Derek Atkins, SB '93 MIT EE, SM '95 MIT Media Laboratory
       Member, MIT Student Information Processing Board  (SIPB)
       URL: http://web.mit.edu/warlord/    PP-ASEL-IA     N1NWH
       warlord@MIT.EDU                        PGP key available

home help back first fref pref prev next nref lref last post