From 9b5e304ccedc8f0f7ce2342e4d9c621417dd1c1e Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 28 Sep 2010 13:07:53 +1000 Subject: heimdal Add support for extracting a particular KVNO from the database This should allow master key rollover. (but the real reason is to allow multiple krbtgt accounts, as used by Active Directory to implement RODC support) Andrew Bartlett --- source4/heimdal/kdc/kerberos5.c | 5 ++-- source4/heimdal/kdc/krb5tgs.c | 51 +++++++++++++++++++++++++++----------- source4/heimdal/kdc/misc.c | 8 ++++++ source4/heimdal/kdc/windc.c | 3 ++- source4/heimdal/kdc/windc_plugin.h | 1 + source4/heimdal/lib/hdb/hdb.h | 3 ++- source4/heimdal/lib/hdb/keytab.c | 2 +- 7 files changed, 54 insertions(+), 19 deletions(-) (limited to 'source4/heimdal') diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c index c3e94757e3..05df86e143 100644 --- a/source4/heimdal/kdc/kerberos5.c +++ b/source4/heimdal/kdc/kerberos5.c @@ -988,7 +988,8 @@ _kdc_as_rep(krb5_context context, */ ret = _kdc_db_fetch(context, config, client_princ, - HDB_F_GET_CLIENT | flags, &clientdb, &client); + HDB_F_GET_CLIENT | flags, 0, + &clientdb, &client); if(ret){ const char *msg = krb5_get_error_message(context, ret); kdc_log(context, config, 0, "UNKNOWN -- %s: %s", client_name, msg); @@ -999,7 +1000,7 @@ _kdc_as_rep(krb5_context context, ret = _kdc_db_fetch(context, config, server_princ, HDB_F_GET_SERVER|HDB_F_GET_KRBTGT, - NULL, &server); + 0, NULL, &server); if(ret){ const char *msg = krb5_get_error_message(context, ret); kdc_log(context, config, 0, "UNKNOWN -- %s: %s", server_name, msg); diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c index dd14ae6513..3560a0df66 100644 --- a/source4/heimdal/kdc/krb5tgs.c +++ b/source4/heimdal/kdc/krb5tgs.c @@ -281,8 +281,10 @@ check_PAC(krb5_context context, const krb5_principal client_principal, hdb_entry_ex *client, hdb_entry_ex *server, + hdb_entry_ex *krbtgt, const EncryptionKey *server_key, - const EncryptionKey *krbtgt_key, + const EncryptionKey *krbtgt_check_key, + const EncryptionKey *krbtgt_sign_key, EncTicketPart *tkt, krb5_data *rspac, int *signedpath) @@ -325,14 +327,14 @@ check_PAC(krb5_context context, ret = krb5_pac_verify(context, pac, tkt->authtime, client_principal, - krbtgt_key, NULL); + krbtgt_check_key, NULL); if (ret) { krb5_pac_free(context, pac); return ret; } ret = _kdc_pac_verify(context, client_principal, - client, server, &pac); + client, server, krbtgt, &pac); if (ret) { krb5_pac_free(context, pac); return ret; @@ -341,7 +343,7 @@ check_PAC(krb5_context context, ret = _krb5_pac_sign(context, pac, tkt->authtime, client_principal, - server_key, krbtgt_key, rspac); + server_key, krbtgt_sign_key, rspac); krb5_pac_free(context, pac); @@ -1156,7 +1158,7 @@ tgs_parse_request(krb5_context context, ap_req.ticket.sname, ap_req.ticket.realm); - ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, NULL, krbtgt); + ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, ap_req.ticket.enc_part.kvno, NULL, krbtgt); if(ret) { const char *msg = krb5_get_error_message(context, ret); @@ -1454,6 +1456,8 @@ tgs_build_reply(krb5_context context, krb5_kvno kvno; krb5_data rspac; + hdb_entry_ex *krbtgt_out = NULL; + METHOD_DATA enc_pa_data; PrincipalName *s; @@ -1463,7 +1467,8 @@ tgs_build_reply(krb5_context context, char opt_str[128]; int signedpath = 0; - Key *tkey; + Key *tkey_check; + Key *tkey_sign; memset(&sessionkey, 0, sizeof(sessionkey)); memset(&adtkt, 0, sizeof(adtkt)); @@ -1495,7 +1500,7 @@ tgs_build_reply(krb5_context context, } _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm); ret = _kdc_db_fetch(context, config, p, - HDB_F_GET_CLIENT|HDB_F_GET_SERVER, + HDB_F_GET_KRBTGT, t->enc_part.kvno, NULL, &uu); krb5_free_principal(context, p); if(ret){ @@ -1548,7 +1553,7 @@ tgs_build_reply(krb5_context context, server_lookup: ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | HDB_F_CANON, - NULL, &server); + 0, NULL, &server); if(ret){ const char *new_rlm, *msg; @@ -1609,7 +1614,7 @@ server_lookup: } ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | HDB_F_CANON, - &clientdb, &client); + 0, &clientdb, &client); if(ret) { const char *krbtgt_realm, *msg; @@ -1704,15 +1709,31 @@ server_lookup: */ ret = hdb_enctype2key(context, &krbtgt->entry, - krbtgt_etype, &tkey); + krbtgt_etype, &tkey_check); if(ret) { kdc_log(context, config, 0, "Failed to find key for krbtgt PAC check"); goto out; } + /* Now refetch the krbtgt, but get the current kvno (the sign check may have been on an old kvno) */ + ret = _kdc_db_fetch(context, config, krbtgt->entry.principal, HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out); + if (ret) { + kdc_log(context, config, 0, + "Failed to find krbtgt in DB for krbtgt PAC signature"); + goto out; + } + + ret = hdb_enctype2key(context, &krbtgt_out->entry, + krbtgt_etype, &tkey_sign); + if(ret) { + kdc_log(context, config, 0, + "Failed to find key for krbtgt PAC signature"); + goto out; + } + ret = check_PAC(context, config, cp, - client, server, ekey, &tkey->key, + client, server, krbtgt, ekey, &tkey_check->key, &tkey_sign->key, tgt, &rspac, &signedpath); if (ret) { const char *msg = krb5_get_error_message(context, ret); @@ -1814,7 +1835,7 @@ server_lookup: krb5_pac p = NULL; krb5_data_free(&rspac); ret = _kdc_db_fetch(context, config, client_principal, HDB_F_GET_CLIENT | HDB_F_CANON, - &s4u2self_impersonated_clientdb, &s4u2self_impersonated_client); + 0, &s4u2self_impersonated_clientdb, &s4u2self_impersonated_client); if (ret) { const char *msg; @@ -1840,7 +1861,7 @@ server_lookup: if (p != NULL) { ret = _krb5_pac_sign(context, p, ticket->ticket.authtime, s4u2self_impersonated_client->entry.principal, - ekey, &tkey->key, + ekey, &tkey_sign->key, &rspac); krb5_pac_free(context, p); if (ret) { @@ -2070,7 +2091,7 @@ server_lookup: spn, client, cp, - krbtgt, + krbtgt_out, krbtgt_etype, spp, &rspac, @@ -2084,6 +2105,8 @@ out: krb5_data_free(&rspac); krb5_free_keyblock_contents(context, &sessionkey); + if(krbtgt_out) + _kdc_free_ent(context, krbtgt_out); if(server) _kdc_free_ent(context, server); if(client) diff --git a/source4/heimdal/kdc/misc.c b/source4/heimdal/kdc/misc.c index 39f91dcf10..3080748463 100644 --- a/source4/heimdal/kdc/misc.c +++ b/source4/heimdal/kdc/misc.c @@ -40,12 +40,19 @@ _kdc_db_fetch(krb5_context context, krb5_kdc_configuration *config, krb5_const_principal principal, unsigned flags, + krb5int32 *kvno_ptr, HDB **db, hdb_entry_ex **h) { hdb_entry_ex *ent; krb5_error_code ret; int i; + unsigned kvno; + + if (kvno_ptr) { + kvno = *kvno_ptr; + flags |= HDB_F_KVNO_SPECIFIED; + } ent = calloc (1, sizeof (*ent)); if (ent == NULL) { @@ -88,6 +95,7 @@ _kdc_db_fetch(krb5_context context, config->db[i], principal, flags | HDB_F_DECRYPT, + kvno, ent); krb5_free_principal(context, enterprise_principal); diff --git a/source4/heimdal/kdc/windc.c b/source4/heimdal/kdc/windc.c index 524bc90d90..a8f1eb15d1 100644 --- a/source4/heimdal/kdc/windc.c +++ b/source4/heimdal/kdc/windc.c @@ -86,6 +86,7 @@ _kdc_pac_verify(krb5_context context, const krb5_principal client_principal, hdb_entry_ex *client, hdb_entry_ex *server, + hdb_entry_ex *krbtgt, krb5_pac *pac) { if (windcft == NULL) { @@ -93,7 +94,7 @@ _kdc_pac_verify(krb5_context context, return EINVAL; } return (windcft->pac_verify)(windcctx, context, - client_principal, client, server, pac); + client_principal, client, server, krbtgt, pac); } krb5_error_code diff --git a/source4/heimdal/kdc/windc_plugin.h b/source4/heimdal/kdc/windc_plugin.h index 0ec8e066c7..037fc8cbda 100644 --- a/source4/heimdal/kdc/windc_plugin.h +++ b/source4/heimdal/kdc/windc_plugin.h @@ -60,6 +60,7 @@ typedef krb5_error_code const krb5_principal, struct hdb_entry_ex *, struct hdb_entry_ex *, + struct hdb_entry_ex *, krb5_pac *); typedef krb5_error_code diff --git a/source4/heimdal/lib/hdb/hdb.h b/source4/heimdal/lib/hdb/hdb.h index 469a330812..ca67d2ddd8 100644 --- a/source4/heimdal/lib/hdb/hdb.h +++ b/source4/heimdal/lib/hdb/hdb.h @@ -54,6 +54,7 @@ enum hdb_lockop{ HDB_RLOCK, HDB_WLOCK }; #define HDB_F_GET_ANY 28 /* fetch any of client,server,krbtgt */ #define HDB_F_CANON 32 /* want canonicalition */ #define HDB_F_ADMIN_DATA 64 /* want data that kdc don't use */ +#define HDB_F_KVNO_SPECIFIED 128 /* we want a particular KVNO */ /* hdb_capability_flags */ #define HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL 1 @@ -122,7 +123,7 @@ typedef struct HDB{ * should be fetch: client, server, krbtgt. */ krb5_error_code (*hdb_fetch)(krb5_context, struct HDB*, - krb5_const_principal, unsigned, + krb5_const_principal, unsigned, unsigned, hdb_entry_ex*); /** * Store an entry to database diff --git a/source4/heimdal/lib/hdb/keytab.c b/source4/heimdal/lib/hdb/keytab.c index 925ff67c58..524cea6f45 100644 --- a/source4/heimdal/lib/hdb/keytab.c +++ b/source4/heimdal/lib/hdb/keytab.c @@ -213,7 +213,7 @@ hdb_get_entry(krb5_context context, ret = (*db->hdb_fetch)(context, db, principal, HDB_F_DECRYPT| HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT, - &ent); + 0, &ent); if(ret == HDB_ERR_NOENTRY) { ret = KRB5_KT_NOTFOUND; -- cgit