heimdal Add support for extracting a particular KVNO from the database
authorAndrew Bartlett <abartlet@samba.org>
Tue, 28 Sep 2010 03:07:53 +0000 (13:07 +1000)
committerAndrew Bartlett <abartlet@samba.org>
Tue, 28 Sep 2010 18:23:07 +0000 (04:23 +1000)
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
source4/heimdal/kdc/krb5tgs.c
source4/heimdal/kdc/misc.c
source4/heimdal/kdc/windc.c
source4/heimdal/kdc/windc_plugin.h
source4/heimdal/lib/hdb/hdb.h
source4/heimdal/lib/hdb/keytab.c

index c3e94757e38dbc4d549f5fc948351c5a53fe67f6..05df86e143248b3a3c2aba59c5b95fe9811401d2 100644 (file)
@@ -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);
index dd14ae6513c2d0ad91c4f81d37a8fecba029476c..3560a0df668c039eb5c8b6f142c8f99deaac4285 100644 (file)
@@ -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)
index 39f91dcf10fe0cadbe6a1a123e22bfdd8a8025a2..3080748463887e5c41bfba24cc7d03aa8d725c51 100644 (file)
@@ -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);
 
index 524bc90d90cb0347655c118904fb08ee7c87de2f..a8f1eb15d1f45595056b8146c1dde92090234024 100644 (file)
@@ -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
index 0ec8e066c7395292d7ed7cbf25a8cdbcd03bba2a..037fc8cbdabd7edefd8f7e5688b12318e27d628a 100644 (file)
@@ -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
index 469a330812785b076eef79bd6440b9eb44200ea5..ca67d2ddd838f71a4597505562758ae620a14d5e 100644 (file)
@@ -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
index 925ff67c5849868d7bda24540463bbeb50071cb7..524cea6f4589d220ee779c2e74bb82a3f2d31b9f 100644 (file)
@@ -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;