Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/netbsd-1-5]: src/usr.bin/login Pull up revision 1.15 (requested by aidan):



details:   https://anonhg.NetBSD.org/src/rev/62709597080c
branches:  netbsd-1-5
changeset: 489435:62709597080c
user:      aidan <aidan%NetBSD.org@localhost>
date:      Mon Sep 11 23:50:13 2000 +0000

description:
Pull up revision 1.15 (requested by aidan):
  Make login check the returned TGT against the local keytab, when using krb5
  for authentication.  This closes a potential man-in-the-middle attack, where
  an intruder can forge a response to login's AS-request, and gain access to
  the host.

diffstat:

 usr.bin/login/k5login.c |  146 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 144 insertions(+), 2 deletions(-)

diffs (193 lines):

diff -r 499e0ae59fe4 -r 62709597080c usr.bin/login/k5login.c
--- a/usr.bin/login/k5login.c   Mon Sep 11 22:13:12 2000 +0000
+++ b/usr.bin/login/k5login.c   Mon Sep 11 23:50:13 2000 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: k5login.c,v 1.12.2.2 2000/08/09 17:49:40 thorpej Exp $ */
+/*     $NetBSD: k5login.c,v 1.12.2.3 2000/09/11 23:50:13 aidan Exp $   */
 
 /*-
  * Copyright (c) 1990 The Regents of the University of California.
@@ -33,12 +33,29 @@
  * SUCH DAMAGE.
  */
 
+/*
+ * Copyright (c) 1980, 1987, 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
 #include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)klogin.c   5.11 (Berkeley) 7/12/92";
 #endif
-__RCSID("$NetBSD: k5login.c,v 1.12.2.2 2000/08/09 17:49:40 thorpej Exp $");
+__RCSID("$NetBSD: k5login.c,v 1.12.2.3 2000/09/11 23:50:13 aidan Exp $");
 #endif /* not lint */
 
 #ifdef KERBEROS5
@@ -52,6 +69,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <errno.h>
 
 #define KRB5_DEFAULT_OPTIONS 0
 #define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */
@@ -72,6 +90,7 @@
 
 int k5_read_creds __P((char *));
 int k5_write_creds __P((void));
+int k5_verify_creds __P((krb5_context, krb5_ccache));
 int k5login __P((struct passwd *, char *, char *, char *));
 void k5destroy __P((void));
 
@@ -83,6 +102,125 @@
 #endif
 
 /*
+ * Verify the Kerberos ticket-granting ticket just retrieved for the
+ * user.  If the Kerberos server doesn't respond, assume the user is
+ * trying to fake us out (since we DID just get a TGT from what is
+ * supposedly our KDC).  If the host/<host> service is unknown (i.e.,
+ * the local keytab doesn't have it), let her in.
+ *
+ * Returns 1 for confirmation, -1 for failure, 0 for uncertainty.
+ */
+int
+k5_verify_creds(c, ccache)
+       krb5_context c;
+       krb5_ccache ccache;
+{
+       char phost[MAXHOSTNAMELEN];
+       int retval, have_keys;
+       krb5_principal princ;
+       krb5_keyblock *kb = 0;
+       krb5_error_code kerror;
+       krb5_data packet;
+       krb5_auth_context auth_context = NULL;
+       krb5_ticket *ticket = NULL;
+
+       kerror = krb5_sname_to_principal(c, 0, 0, KRB5_NT_SRV_HST, &princ);
+       if (kerror) {
+               com_err("login", kerror, "constructing local service name");
+               return (-1);
+       }
+
+       /* Do we have host/<host> keys? */
+       /* (use default keytab, kvno IGNORE_VNO to get the first match,
+        * and default enctype.) */
+       kerror = krb5_kt_read_service_key(c, NULL, princ, 0, 0, &kb);
+       if (kb)
+               krb5_free_keyblock(c, kb);
+       /* any failure means we don't have keys at all. */
+       have_keys = kerror ? 0 : 1;
+
+       /* XXX there should be a krb5 function like mk_req, but taking a full
+        * principal, instead of a service/hostname.  (Did I miss one?) */
+       gethostname(phost, sizeof(phost));
+       phost[sizeof(phost) - 1] = '\0';
+
+       /* talk to the kdc and construct the ticket */
+       kerror = krb5_mk_req(c, &auth_context, 0, "host", phost,
+                            0, ccache, &packet);
+       /* wipe the auth context for rd_req */
+       if (auth_context) {
+               krb5_auth_con_free(c, auth_context);
+               auth_context = NULL;
+       }
+       if (kerror == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) {
+               /* we have a service key, so something should be
+                * in the database, therefore this error packet could
+                * have come from an attacker. */
+               if (have_keys) {
+                       retval = -1;
+                       goto EGRESS;
+               }
+               /* but if it is unknown and we've got no key, we don't
+                * have any security anyhow, so it is ok. */
+               else {
+                       retval = 0;
+                       goto EGRESS;
+               }
+       }
+       else if (kerror) {
+               com_err("login", kerror,
+                       "Unable to verify Kerberos V5 TGT: %s", phost);
+               syslog(LOG_NOTICE|LOG_AUTH, "Kerberos V5 TGT bad: %s", 
+                      error_message(kerror));
+               retval = -1;
+               goto EGRESS;
+       }
+       /* got ticket, try to use it */
+       kerror = krb5_rd_req(c, &auth_context, &packet,
+                            princ, NULL, NULL, &ticket);
+       if (kerror) {
+               if (!have_keys) {
+                       /* The krb5 errors aren't specified well, but I think
+                        * these values cover the cases we expect. */
+                       switch (kerror) {
+                       case ENOENT:    /* no keytab */
+                       case KRB5_KT_NOTFOUND:
+                               retval = 0;
+                               break;
+                       default:
+                               /* unexpected error: fail */
+                               retval = -1;
+                               break;
+                       }
+               }
+               else {
+                       /* we have keys, so if we got any error, we could be
+                        * under attack. */
+                       retval = -1;
+               }
+               com_err("login", kerror, "Unable to verify host ticket");
+               syslog(LOG_NOTICE|LOG_AUTH, "can't verify v5 ticket: %s; %s\n",
+                      error_message(kerror),
+                      retval
+                        ? "keytab found, assuming failure"
+                        : "no keytab found, assuming success");
+               goto EGRESS;
+       }
+       /*
+        * The host/<host> ticket has been received _and_ verified.
+        */
+       retval = 1;
+
+       /* do cleanup and return */
+EGRESS:
+       if (auth_context)
+               krb5_auth_con_free(c, auth_context);
+       krb5_free_principal(c, princ);
+       /* possibly ticket and packet need freeing here as well */
+       return (retval);
+}
+
+/*
  * Attempt to read forwarded kerberos creds
  *
  * return 0 on success (forwarded creds in memory)
@@ -313,6 +451,10 @@
 
            return(1);
        }
+       if (k5_verify_creds(kcontext, ccache) < 0) {
+           return(1);
+       }
+
 
        /* Success */
        notickets = 0;



Home | Main Index | Thread Index | Old Index