From: Theodore Tso Date: Sat, 2 Sep 1995 03:43:05 +0000 (+0000) Subject: kdc_preauth.c: New file, to contain the server-side preauthentication X-Git-Tag: krb5-1.0-beta6~1200 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=c1cfefcfea75466ebfc82120d665f1a5752b7314;p=krb5.git 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. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@6656 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/kdc/ChangeLog b/src/kdc/ChangeLog index 825b30c8b..ac3ef1c5f 100644 --- a/src/kdc/ChangeLog +++ b/src/kdc/ChangeLog @@ -1,3 +1,15 @@ +Fri Sep 1 23:28:29 1995 Theodore Y. Ts'o + + * 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 diff --git a/src/kdc/Makefile.in b/src/kdc/Makefile.in index 99e91114a..3145e1cac 100644 --- a/src/kdc/Makefile.in +++ b/src/kdc/Makefile.in @@ -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 \ diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c index 76086e33c..a80d282f4 100644 --- a/src/kdc/do_as_req.c +++ b/src/kdc/do_as_req.c @@ -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 = ""; - /* - * 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 index 000000000..07018e394 --- /dev/null +++ b/src/kdc/kdc_preauth.c @@ -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 + +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; +} + + + diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h index 5e3960c2f..6d5e5babd 100644 --- a/src/kdc/kdc_util.h +++ b/src/kdc/kdc_util.h @@ -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 *));