kdc_preauth.c: New file, to contain the server-side preauthentication
authorTheodore Tso <tytso@mit.edu>
Sat, 2 Sep 1995 03:43:05 +0000 (03:43 +0000)
committerTheodore Tso <tytso@mit.edu>
Sat, 2 Sep 1995 03:43:05 +0000 (03:43 +0000)
routines.

do_as_req.c (process_as_req): Move preauthentication code to
kdc_preauth.c, for better modularity.

do_as_req.c (prepare_error_as): Add new argument to this function so
that the e_data field may be passed in and included in the KRB_ERROR
messsage which is passed back to the user.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@6656 dc483132-0cff-0310-8789-dd5450dbe970

src/kdc/ChangeLog
src/kdc/Makefile.in
src/kdc/do_as_req.c
src/kdc/kdc_preauth.c [new file with mode: 0644]
src/kdc/kdc_util.h

index 825b30c8b1ef6c66ede37531ccb3ba89b2f0d5f4..ac3ef1c5fb106f4c02d5a31e1388ff04d94de80c 100644 (file)
@@ -1,3 +1,15 @@
+Fri Sep  1 23:28:29 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+       * kdc_preauth.c: New file, to contain the server-side
+               preauthentication routines.
+
+       * do_as_req.c (process_as_req): Move preauthentication code to
+               kdc_preauth.c, for better modularity.
+
+       * do_as_req.c (prepare_error_as): Add new argument to this
+               function so that the e_data field may be passed in and
+               included in the KRB_ERROR messsage which is passed back to
+               the user.
 
 Mon Aug 21 17:03:53 EDT 1995   Paul Park       (pjpark@mit.edu)
        * main.c - Interpret -k and -e arguments as strings instead of string
index 99e91114a09322e3f02a718bb788a7ebb038a51f..3145e1cac3734fba280918f4a129294b1edebf1d 100644 (file)
@@ -13,6 +13,7 @@ SRCS= \
        $(srcdir)/do_as_req.c \
        $(srcdir)/do_tgs_req.c \
        $(srcdir)/kdc_util.c \
+       $(srcdir)/kdc_preauth.c \
        $(srcdir)/main.c \
        $(srcdir)/network.c \
        $(srcdir)/policy.c \
@@ -26,6 +27,7 @@ OBJS= \
        do_as_req.o \
        do_tgs_req.o \
        kdc_util.o \
+       kdc_preauth.o \
        main.o \
        network.o \
        policy.o \
index 76086e33c53280745f6fc3eaf19726640f575fd9..a80d282f45d55cd813af55752412ffbc23610ca4 100644 (file)
@@ -44,6 +44,7 @@
 
 static krb5_error_code prepare_error_as PROTOTYPE((krb5_kdc_req *,
                                                   int,
+                                                  krb5_data *, 
                                                   krb5_data **));
 /*
  * This routine is called to verify the preauthentication information
@@ -105,7 +106,7 @@ krb5_data **response;                       /* filled in with a response packet */
     krb5_enc_tkt_part enc_tkt_reply;
     krb5_error_code retval;
     int c_nprincs = 0, s_nprincs = 0;
-    int pwreq, pa_id, pa_flags;
+    int pa_id, pa_flags;
     krb5_boolean more;
     krb5_timestamp kdc_time, authtime;
     krb5_keyblock *session_key = 0;
@@ -113,7 +114,6 @@ krb5_data **response;                       /* filled in with a response packet */
     krb5_enctype useetype;
     krb5_pa_data *padat_tmp[2], padat_local;
     krb5_data salt_data;
-    static krb5_principal cpw = 0;
     char *status;
     krb5_encrypt_block eblock;
     krb5_key_data  *server_key, *client_key;
@@ -131,19 +131,19 @@ krb5_data **response;                     /* filled in with a response packet */
 
     if (!request->client)
        return(prepare_error_as(request, KDC_ERR_C_PRINCIPAL_UNKNOWN,
-                               response));
+                               0, response));
     if ((retval = krb5_unparse_name(kdc_context, request->client, &cname))) {
        krb5_klog_syslog(LOG_INFO, "AS_REQ: %s while unparsing client name",
               error_message(retval));
        return(prepare_error_as(request, KDC_ERR_C_PRINCIPAL_UNKNOWN,
-                               response));
+                               0, response));
     }
     if ((retval = krb5_unparse_name(kdc_context, request->server, &sname))) {
        free(cname);
        krb5_klog_syslog(LOG_INFO, "AS_REQ: %s while unparsing server name",
               error_message(retval));
        return(prepare_error_as(request, KDC_ERR_S_PRINCIPAL_UNKNOWN,
-                               response));
+                               0, response));
     }
 #ifdef KRB5_USE_INET
     if (from->address->addrtype == ADDRTYPE_INET)
@@ -152,25 +152,6 @@ krb5_data **response;                      /* filled in with a response packet */
     if (!fromstring)
        fromstring = "<unknown>";
 
-    /*
-     * Special considerations are allowed when changing passwords. Is
-     * this request for changepw?
-     *
-     * XXX This logic should be moved someplace else, perhaps the
-     * site-specific policiy file....
-     */
-    pwreq = 0;
-    if (!cpw) {
-           retval = krb5_parse_name(kdc_context, "changepw/kerberos", &cpw);
-           if (retval)
-                   goto errout;
-           free(krb5_princ_realm(kdc_context, cpw)->data);
-           krb5_princ_realm(kdc_context, cpw)->data = 0;
-    }
-    krb5_princ_realm(kdc_context, cpw)->data = krb5_princ_realm(kdc_context, request->server)->data;
-    if (krb5_principal_compare(kdc_context, request->server, cpw))
-           pwreq++;
-
     c_nprincs = 1;
     if ((retval = krb5_db_get_principal(kdc_context, request->client, &client, 
                                        &c_nprincs, &more))) {
@@ -179,14 +160,14 @@ krb5_data **response;                     /* filled in with a response packet */
     }
     if (more) {
        retval = prepare_error_as(request, KDC_ERR_PRINCIPAL_NOT_UNIQUE,
-                                 response);
+                                 0, response);
        goto errout;
     } else if (c_nprincs != 1) {
 #ifdef KRBCONF_VAGUE_ERRORS
-       retval = prepare_error_as(request, KRB_ERR_GENERIC, response);
+       retval = prepare_error_as(request, KRB_ERR_GENERIC, 0, response);
 #else
        retval = prepare_error_as(request, KDC_ERR_C_PRINCIPAL_UNKNOWN,
-                                 response);
+                                 0, response);
 #endif
        goto errout;
     }
@@ -199,11 +180,11 @@ krb5_data **response;                     /* filled in with a response packet */
     }
     if (more) {
        retval = prepare_error_as(request, KDC_ERR_PRINCIPAL_NOT_UNIQUE,
-                                 response);
+                                 0, response);
        goto errout;
     } else if (s_nprincs != 1) {
        retval = prepare_error_as(request, KDC_ERR_S_PRINCIPAL_UNKNOWN,
-                                 response);
+                                 0, response);
        goto errout;
     }
 
@@ -218,7 +199,7 @@ krb5_data **response;                       /* filled in with a response packet */
                                      kdc_time, &status))) {
        krb5_klog_syslog(LOG_INFO, "AS_REQ: %s: host %s, %s for %s", status,
                   fromstring, cname, sname);
-       retval = prepare_error_as(request, retval, response);
+       retval = prepare_error_as(request, retval, 0, response);
        goto errout;
     }
       
@@ -248,7 +229,7 @@ krb5_data **response;                       /* filled in with a response packet */
     /* unsupported etype */
     krb5_klog_syslog(LOG_INFO,"AS_REQ: BAD ENCRYPTION TYPE: host %s, %s for %s",
                      fromstring, cname, sname);
-    retval = prepare_error_as(request, KDC_ERR_ETYPE_NOSUPP, response);
+    retval = prepare_error_as(request, KDC_ERR_ETYPE_NOSUPP, 0, response);
     goto errout;
 
 got_a_key:;
@@ -362,16 +343,15 @@ got_a_key:;
             krb5_klog_syslog(LOG_INFO, "AS_REQ: PREAUTH FAILED: host %s, %s for %s (%s)",
                   fromstring, cname, sname, error_message(retval));
 #ifdef KRBCONF_VAGUE_ERRORS
-            retval = prepare_error_as(request, KRB_ERR_GENERIC, response);
+            retval = prepare_error_as(request, KRB_ERR_GENERIC, 0, response);
 #else
            retval -= ERROR_TABLE_BASE_krb5;
            if ((retval < 0) || (retval > 127))
                    retval = KDC_ERR_PREAUTH_FAILED;
-            retval = prepare_error_as(request, retval, response);
+            retval = prepare_error_as(request, retval, 0, response);
 #endif
            goto errout;
        } 
-
        setflag(enc_tkt_reply.flags, TKT_FLG_PRE_AUTH);
        /*
         * If pa_type is one in which additional hardware authentication
@@ -383,23 +363,23 @@ got_a_key:;
 
     /*
      * Final check before handing out ticket: If the client requires
-     * Hardware authentication, verify ticket flag is set
-     */  
-
-    if (isflagset(client.attributes, KRB5_KDB_REQUIRES_HW_AUTH) &&
-       !isflagset(enc_tkt_reply.flags, TKT_FLG_HW_AUTH)) {
-
-         /* Of course their are always exceptions, in this case if the
-            service requested is for changing of the key (password), then
-            if TKT_FLG_PRE_AUTH is set allow it. */
+     * preauthentication, verify that the proper kind of
+     * preauthentication was carried out.
+     */
+    status = missing_required_preauth(&client, &server, &enc_tkt_reply);
+    if (status) {
+       krb5_data e_data;
        
-         if (!pwreq || !(enc_tkt_reply.flags & TKT_FLG_PRE_AUTH)){
-              krb5_klog_syslog(LOG_INFO, "AS_REQ: Needed HW preauth: host %s, %s for %s",
-                    fromstring, cname, sname);
-              retval = prepare_error_as(request, KRB_ERR_GENERIC, response);
-             goto errout;
-         }
-      }
+       krb5_klog_syslog(LOG_INFO, "AS_REQ: Needed %s: host %s, %s for %s",
+                        status, fromstring, cname, sname);
+    
+       get_preauth_hint_list(&client, &server, &e_data);
+       retval = prepare_error_as(request, KDC_ERR_PREAUTH_REQUIRED,
+                                 &e_data, response);
+       if (e_data.data)
+           free(e_data.data);
+       goto errout;
+    }
 
     ticket_reply.enc_part2 = &enc_tkt_reply;
 
@@ -439,7 +419,7 @@ got_a_key:;
        krb5_klog_syslog(LOG_INFO,
                         "AS_REQ: CANNOT FIND CLIENT KEY: host %s, %s for %s",
                         fromstring, cname, sname);
-       retval = prepare_error_as(request, KDC_ERR_ETYPE_NOSUPP, response);
+       retval = prepare_error_as(request, KDC_ERR_ETYPE_NOSUPP, 0, response);
        goto errout;
     }
 
@@ -588,9 +568,10 @@ errout:
 }
 
 static krb5_error_code
-prepare_error_as (request, error, response)
+prepare_error_as (request, error, e_data, response)
 register krb5_kdc_req *request;
 int error;
+krb5_data *e_data;
 krb5_data **response;
 {
     krb5_error errpkt;
@@ -632,8 +613,12 @@ krb5_data **response;
        free(errpkt.text.data);
        return ENOMEM;
     }
-    errpkt.e_data.length = 0;
-    errpkt.e_data.data = 0;
+    if (e_data) {
+       errpkt.e_data = *e_data;
+    } else {
+       errpkt.e_data.length = 0;
+       errpkt.e_data.data = 0;
+    }
 
     retval = krb5_mk_error(kdc_context, &errpkt, scratch);
     free(errpkt.text.data);
diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c
new file mode 100644 (file)
index 0000000..07018e3
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * kdc/kdc_preauth.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * Preauthentication routines for the KDC.
+ */
+
+#include "k5-int.h"
+#include "kdc_util.h"
+#include "extern.h"
+#include <stdio.h>
+
+typedef krb5_error_code (verify_proc)
+    KRB5_PROTOTYPE((krb5_context, krb5_principal client,
+                   krb5_address **src_addr,
+                   krb5_data *data));
+
+typedef krb5_error_code (edata_proc)
+    KRB5_PROTOTYPE((krb5_context, krb5_db_entry *client,
+                   krb5_pa_data *data));
+
+typedef struct _krb5_preauth_systems {
+    int                type;
+    int                flags;
+    edata_proc *get_edata;
+    verify_proc        *verify;
+} krb5_preauth_systems;
+
+/*
+ * Preauth property flags
+ */
+#define PA_ENCRYPT     0x00000001
+#define PA_HARDWARE    0x00000002
+
+static krb5_preauth_systems preauth_systems[] = {
+    {
+        KRB5_PADATA_ENC_UNIX_TIME,
+        PA_ENCRYPT,
+        0,
+       0,
+    },
+    {
+       KRB5_PADATA_ENC_SANDIA_SECURID,
+       PA_ENCRYPT | PA_HARDWARE,
+       0,
+       0,
+    },
+    { -1,}
+};
+
+#define MAX_PREAUTH_SYSTEMS (sizeof(preauth_systems)/sizeof(preauth_systems[0]))
+
+const char *missing_required_preauth(client, server, enc_tkt_reply)
+    krb5_db_entry *client, *server;
+    krb5_enc_tkt_part *enc_tkt_reply;
+{
+#if 0
+    /*
+     * If this is the pwchange service, and the pre-auth bit is set,
+     * allow it even if the HW preauth would normally be required.
+     * 
+     * Sandia national labs wanted this for some strange reason... we
+     * leave it disabled normally.
+     */
+    if (isflagset(server->attributes, KRB5_KDB_PWCHANGE_SERVICE) &&
+       isflagset(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH))
+       return 0;
+#endif
+    
+    if (isflagset(client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) &&
+        !isflagset(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH))
+       return "preauth";
+    
+    if (isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH) &&
+       !isflagset(enc_tkt_reply->flags, TKT_FLG_HW_AUTH))
+       return "HW preauth";
+
+    return 0;
+}
+
+void get_preauth_hint_list(client, server, e_data)
+    krb5_db_entry *client, *server;
+    krb5_data *e_data;
+{
+    int hw_only;
+    krb5_preauth_systems *ap;
+    krb5_pa_data **pa_data, **pa;
+    krb5_data *edat;
+    krb5_error_code retval;
+    
+    /* Zero these out in case we need to abort */
+    e_data->length = 0;
+    e_data->data = 0;
+    
+    hw_only = isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH);
+    pa_data = malloc(sizeof(krb5_pa_data *) * (MAX_PREAUTH_SYSTEMS+1));
+    if (pa_data == 0)
+       return;
+    memset(pa_data, 0, sizeof(krb5_pa_data *) * (MAX_PREAUTH_SYSTEMS+1));
+    pa = pa_data;
+
+    for (ap = preauth_systems; ap->type != -1; ap++) {
+       if (hw_only && !(ap->flags & PA_HARDWARE))
+           continue;
+       *pa = malloc(sizeof(krb5_pa_data));
+       if (*pa == 0)
+           goto errout;
+       memset(pa, 0, sizeof(krb5_pa_data));
+       (*pa)->magic = KV5M_PA_DATA;
+       (*pa)->pa_type = ap->type;
+       if (ap->get_edata)
+           (ap->get_edata)(kdc_context, client, *pa);
+       pa++;
+    }
+    retval = encode_krb5_padata_sequence((const krb5_pa_data **) pa_data,
+                                        &edat);
+    if (retval)
+       goto errout;
+    *e_data = *edat;
+    free(edat);
+
+errout:
+    krb5_free_pa_data(kdc_context, pa_data);
+    return;
+}
+
+
+                       
index 5e3960c2f9d3c48246b4d3cf2a3db6e8a68730fc..6d5e5babda2a02685e48dba23c579046a4003e89 100644 (file)
@@ -109,7 +109,14 @@ int against_local_policy_as PROTOTYPE((krb5_kdc_req *, krb5_db_entry,
 int against_local_policy_tgs PROTOTYPE((krb5_kdc_req *, krb5_db_entry,
                                        krb5_ticket *, char **));
 
-
+/* kdc_preauth.c */
+const char * missing_required_preauth
+    PROTOTYPE((krb5_db_entry *client, krb5_db_entry *server,
+              krb5_enc_tkt_part *enc_tkt_reply));
+void get_preauth_hint_list PROTOTYPE((krb5_db_entry *client,
+                                    krb5_db_entry *server,
+                                    krb5_data *e_data));
+    
 /* replay.c */
 krb5_boolean kdc_check_lookaside PROTOTYPE((krb5_data *, krb5_data **));
 void kdc_insert_lookaside PROTOTYPE((krb5_data *, krb5_data *));