$NetBSD: patch-at,v 1.2 2000/04/23 19:17:30 thorpej Exp $

--- auth-passwd.c.orig	Wed May 12 04:19:23 1999
+++ auth-passwd.c	Tue Apr 18 11:48:03 2000
@@ -301,29 +301,25 @@
 static int securid_initialized = 0;
 #endif /* HAVE_SECURID */
 
-#ifdef KERBEROS
-#if defined(KRB5)
+#ifdef KRB5
 #include <krb5.h>
 extern  krb5_context ssh_context;
 extern  krb5_auth_context auth_context;
-#else
-#include <krb.h>
 #endif /* KRB5 */
-#endif /* KERBEROS */
 
-#ifdef AFS
-#include <afs/param.h>
-#include <afs/kautils.h>
-#endif /* AFS */
+#ifdef KRB4
+#include <sys/param.h>
+#include <krb.h>
+#endif /* KRB4 */
 
-#if defined(KERBEROS) || defined(AFS_KERBEROS)
+#if defined(KRB4) || defined(KRB5)
 extern char *ticket;
-#endif /* KERBEROS || AFS_KERBEROS */
+#endif /* KRB4 || KRB5 */
 
 /* Tries to authenticate the user using password.  Returns true if
    authentication succeeds. */
 
-#if defined(KERBEROS) && defined(KRB5)
+#ifdef KRB5
 /*
  * This routine with some modification is from the MIT V5B6 appl/bsd/login.c
  *
@@ -479,16 +475,16 @@
                                      0 };
 #endif
 krb5_preauthtype * preauth = preauth_list;
-#endif /* KERBEROS */
+#endif /* KRB5 */
 
 /* Tries to authenticate the user using password.  Returns true if
    authentication succeeds. */
-#ifdef KERBEROS
+#ifdef KRB5
 int auth_password(const char *server_user, const char *password,
                   krb5_principal client)
-#else  /* KERBEROS */
+#else  /* KRB5 */
 int auth_password(const char *server_user, const char *password)
-#endif /* KERBEROS */
+#endif /* KRB5 */
 {
 #if defined(_AIX) && defined(HAVE_AUTHENTICATE)
   char *message;
@@ -505,7 +501,7 @@
     }
 #else /* _AIX41 && HAVE_AUTHENTICATE */
 
-#ifdef KERBEROS
+#ifdef KRB5
   krb5_error_code problem;
   int krb5_options = KDC_OPT_RENEWABLE | KDC_OPT_FORWARDABLE;
   krb5_deltat rlife = 0;
@@ -515,7 +511,7 @@
   krb5_ccache ccache;
   char ccname[80];
   int results;
-#endif  /* KERBEROS */
+#endif  /* KRB5 */
   extern ServerOptions options;
   extern char *crypt(const char *key, const char *salt);
   struct passwd *pw;
@@ -537,10 +533,9 @@
   saved_pw_name = xstrdup(pw->pw_name);
   saved_pw_passwd = xstrdup(pw->pw_passwd);
   
-#if defined(KERBEROS)
-  if (options.kerberos_authentication)
-    {
 #if defined(KRB5)
+  if (options.kerberos_authentication && client != NULL)
+    {
       snprintf(ccname, sizeof(ccname), "FILE:/tmp/krb5cc_l%d", getpid());
       
       if (problem = krb5_cc_resolve(ssh_context, ccname, &ccache))
@@ -658,9 +653,96 @@
               return 0;
             }
         }
+    }
 #endif /* KRB5 */
+#ifdef KRB4
+  if (options.kerberos_authentication)
+    {
+      AUTH_DAT adata;
+      KTEXT_ST tkt;
+      struct hostent *hp;
+      unsigned long faddr;
+      char localhost[MAXHOSTNAMELEN];	/* local host name */
+      char phost[INST_SZ];		/* host instance */
+      char realm[REALM_SZ];		/* local Kerberos realm */
+      int r;
+      
+      /* Try Kerberos password authentication only for non-root
+	 users and only if Kerberos is installed. */
+      if (pw->pw_uid != 0 && krb_get_lrealm(realm, 0) == KSUCCESS) {
+
+	/* Set up our ticket file. */
+	if (!ssh_tf_init(pw->pw_uid)) {
+	  log_msg("Couldn't initialize Kerberos ticket file for %s!",
+		  server_user);
+	  goto kerberos_auth_failure;
+	}
+	/* Try to get TGT using our password. */
+        if ((r = krb_get_pw_in_tkt((char *)server_user, "", realm, "krbtgt",
+             realm, DEFAULT_TKT_LIFE, (char *)password)) != INTK_OK) {
+	  packet_send_debug("Kerberos V4 password authentication for %s "
+			    "failed: %s", server_user, krb_err_txt[r]);
+	  goto kerberos_auth_failure;
+	}
+	/* Successful authentication. */
+	chown(ticket, pw->pw_uid, pw->pw_gid);
+	
+	(void) gethostname(localhost, sizeof(localhost));
+	(void) strncpy(phost, (char *)krb_get_phost(localhost), INST_SZ);
+	phost[INST_SZ-1] = 0;
+	
+	/* Now that we have a TGT, try to get a local "rcmd" ticket to
+	   ensure that we are not talking to a bogus Kerberos server. */
+	r = krb_mk_req(&tkt, KRB4_SERVICE_NAME, phost, realm, 33);
+
+	if (r == KSUCCESS) {
+	  if (!(hp = gethostbyname(localhost))) {
+	    log_msg("Couldn't get local host address!");
+	    goto kerberos_auth_failure;
+	  }
+	  memmove((void *)&faddr, (void *)hp->h_addr, sizeof(faddr));
+
+	  /* Verify our "rcmd" ticket. */
+	  r = krb_rd_req(&tkt, KRB4_SERVICE_NAME, phost, faddr, &adata, "");
+	  if (r == RD_AP_UNDEC) {
+	    /* Probably didn't have a srvtab on localhost. Allow login. */
+	    log_msg("Kerberos V4 TGT for %s unverifiable, no srvtab? "
+		    "krb_rd_req: %s", server_user, krb_err_txt[r]);
+	  }
+	  else if (r != KSUCCESS) {
+	    log_msg("Kerberos V4 %s ticket unverifiable: %s",
+		    KRB4_SERVICE_NAME, krb_err_txt[r]);
+	    goto kerberos_auth_failure;
+	  }
+	}
+	else if (r == KDC_PR_UNKNOWN) {
+	  /* Allow login if no rcmd service exists, but log the error. */
+	  log_msg("Kerberos V4 TGT for %s unverifiable: %s; %s.%s "
+		  "not registered, or srvtab is wrong?", server_user,
+		  krb_err_txt[r], KRB4_SERVICE_NAME, phost);
+	}
+	else {
+	  /* TGT is bad, forget it. Possibly spoofed. */
+	  packet_send_debug("WARNING: Kerberos V4 TGT possibly spoofed for"
+			    "%s: %s", server_user, krb_err_txt[r]);
+	  goto kerberos_auth_failure;
+	}
+	
+	/* Authentication succeeded. */
+	return 1;
+	
+      kerberos_auth_failure:
+	(void) dest_tkt();
+	xfree(ticket);
+	ticket = NULL;
+	if (!options.kerberos_or_local_passwd ) return 0;
+      }
+      else /* Logging in as root or no local Kerberos realm. */
+	packet_send_debug("Unable to authenticate to Kerberos.");
+      
+      /* Fall back to ordinary passwd authentication. */
     }
-#endif /* KERBEROS */
+#endif /* KRB4 */
   
 #ifdef HAVE_SECURID
   /* Support for Security Dynamics SecurId card.