[RFC] kdb: store mkey list in context and permit NULL mkey for kdb_dbe_decrypt_key_data

Sam Hartman hartmans at MIT.EDU
Sat Sep 11 12:37:29 EDT 2010


From: Sam Hartman <hartmans at debian.org>

Previously, code needed to run a loop to find the current master key,
possibly fetch a new master key list and try finding the master key
again around each key decryption.  This was not universally done;
there are cases where only the current master key was used.
In addition, the correct ideom for decrypting key data is too complicated and is unavailable to plugins that do not have access to the master key.
Instead, store the master key list in the dal_handle whenever it is fetched and permit a NULL master key for krb5_dbe_decrypt_key_data.

* Remove APIs for krb5_db_{get|set}_mkey_list
* krb5_db_fetch_mkey_list: memoize master key list in dal_handle
* krb5_db_free_mkey_list: don't free the memoized list; arrange for it to be freed later
* krb5_dbe_decrypt_key_data: Search for correct master key on NULL argument
* change call sites to take advantage
---
 src/include/kdb.h                 |   19 +++++--
 src/kadmin/server/ovsec_kadmd.c   |    6 --
 src/kdc/do_as_req.c               |   44 +---------------
 src/kdc/do_tgs_req.c              |   23 +--------
 src/kdc/kdc_preauth.c             |   65 ++---------------------
 src/kdc/kdc_util.c                |   24 +--------
 src/kdc/main.c                    |    6 --
 src/lib/kadm5/srv/svr_principal.c |   51 +++++-------------
 src/lib/kdb/kdb5.c                |  102 +++++++++++++++++++++++--------------
 src/lib/kdb/kdb5.h                |    3 +
 src/lib/kdb/keytab.c              |   12 +----
 src/lib/kdb/libkdb5.exports       |    2 -
 src/tests/verify/kdb5_verify.c    |    2 +-
 13 files changed, 107 insertions(+), 252 deletions(-)

diff --git a/src/include/kdb.h b/src/include/kdb.h
index d401fd5..97061dc 100644
--- a/src/include/kdb.h
+++ b/src/include/kdb.h
@@ -350,11 +350,6 @@ krb5_error_code krb5_db_iterate ( krb5_context kcontext,
                                   int (*func) (krb5_pointer, krb5_db_entry *),
                                   krb5_pointer func_arg );
 
-krb5_error_code krb5_db_set_mkey_list( krb5_context context,
-                                       krb5_keylist_node * keylist);
-
-krb5_error_code krb5_db_get_mkey_list( krb5_context kcontext,
-                                       krb5_keylist_node ** keylist);
 
 krb5_error_code krb5_db_store_master_key  ( krb5_context kcontext,
                                             char *keyfile,
@@ -382,7 +377,15 @@ krb5_db_fetch_mkey_list( krb5_context    context,
                          const krb5_keyblock * mkey,
                          krb5_kvno             mkvno,
                          krb5_keylist_node  **mkeys_list );
-
+/**
+ * Free a master keylist. The dal_handle holds onto the most recent master
+ * keylist that has been fetched throughout the lifetime of the context; if
+ * this function is called on that keylist, then the dal_handle is updated to
+ * indicate that the keylist should be freed on next call to
+ * krb5_db_fetch_mkey_list() or when the database is closed. Otherwise, the
+ * master_keylist is freed. Either way, the caller must not access this master
+ * keylist after calling this function.
+ */
 void
 krb5_db_free_mkey_list( krb5_context         context,
                         krb5_keylist_node  *mkey_list );
@@ -411,6 +414,10 @@ krb5_db_setup_mkey_name ( krb5_context context,
                           char **fullname,
                           krb5_principal *principal);
 
+/**
+ * Decrypts the key given in @param key_data. If @param mkey is specified, that
+ * master key is used. If @param mkey is NULL, then all master keys are tried.
+ */
 krb5_error_code
 krb5_dbe_decrypt_key_data( krb5_context         context,
                            const krb5_keyblock        * mkey,
diff --git a/src/kadmin/server/ovsec_kadmd.c b/src/kadmin/server/ovsec_kadmd.c
index 6d25a0f..6b55273 100644
--- a/src/kadmin/server/ovsec_kadmd.c
+++ b/src/kadmin/server/ovsec_kadmd.c
@@ -430,12 +430,6 @@ int main(int argc, char *argv[])
         krb5_klog_syslog(LOG_ERR, "Can't set kdb keytab's internal context.");
         goto kterr;
     }
-    /* XXX master_keylist is in guts of lib/kadm5/server_kdb.c */
-    ret = krb5_db_set_mkey_list(hctx, master_keylist);
-    if (ret) {
-        krb5_klog_syslog(LOG_ERR, "Can't set master key list for kdb keytab.");
-        goto kterr;
-    }
     ret = krb5_kt_register(context, &krb5_kt_kdb_ops);
     if (ret) {
         krb5_klog_syslog(LOG_ERR, "Can't register kdb keytab.");
diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c
index fa98ae3..557ae3d 100644
--- a/src/kdc/do_as_req.c
+++ b/src/kdc/do_as_req.c
@@ -115,7 +115,6 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
     const char *status;
     krb5_key_data *server_key, *client_key;
     krb5_keyblock server_keyblock, client_keyblock;
-    krb5_keyblock *mkey_ptr;
     krb5_enctype useenctype;
     krb5_data e_data;
     register int i;
@@ -126,7 +125,6 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
     void *pa_context = NULL;
     int did_log = 0;
     const char *emsg = 0;
-    krb5_keylist_node *tmp_mkey_list;
     struct kdc_request_state *state = NULL;
     krb5_data encoded_req_body;
     krb5_keyblock *as_encrypting_key = NULL;
@@ -461,32 +459,13 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
         goto errout;
     }
 
-    if ((errcode = krb5_dbe_find_mkey(kdc_context, master_keylist, server,
-                                      &mkey_ptr))) {
-        /* try refreshing master key list */
-        /* XXX it would nice if we had the mkvno here for optimization */
-        if (krb5_db_fetch_mkey_list(kdc_context, master_princ,
-                                    &master_keyblock, 0, &tmp_mkey_list) == 0) {
-            krb5_dbe_free_key_list(kdc_context, master_keylist);
-            master_keylist = tmp_mkey_list;
-            if ((errcode = krb5_dbe_find_mkey(kdc_context, master_keylist,
-                                              server, &mkey_ptr))) {
-                status = "FINDING_MASTER_KEY";
-                goto errout;
-            }
-        } else {
-            status = "FINDING_MASTER_KEY";
-            goto errout;
-        }
-    }
-
     /*
      * Convert server->key into a real key
      * (it may be encrypted in the database)
      *
      *  server_keyblock is later used to generate auth data signatures
      */
-    if ((errcode = krb5_dbe_decrypt_key_data(kdc_context, mkey_ptr,
+    if ((errcode = krb5_dbe_decrypt_key_data(kdc_context, NULL,
                                              server_key, &server_keyblock,
                                              NULL))) {
         status = "DECRYPT_SERVER_KEY";
@@ -514,27 +493,8 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
         goto errout;
     }
 
-    if ((errcode = krb5_dbe_find_mkey(kdc_context, master_keylist, client,
-                                      &mkey_ptr))) {
-        /* try refreshing master key list */
-        /* XXX it would nice if we had the mkvno here for optimization */
-        if (krb5_db_fetch_mkey_list(kdc_context, master_princ,
-                                    &master_keyblock, 0, &tmp_mkey_list) == 0) {
-            krb5_dbe_free_key_list(kdc_context, master_keylist);
-            master_keylist = tmp_mkey_list;
-            if ((errcode = krb5_dbe_find_mkey(kdc_context, master_keylist,
-                                              client, &mkey_ptr))) {
-                status = "FINDING_MASTER_KEY";
-                goto errout;
-            }
-        } else {
-            status = "FINDING_MASTER_KEY";
-            goto errout;
-        }
-    }
-
     /* convert client.key_data into a real key */
-    if ((errcode = krb5_dbe_decrypt_key_data(kdc_context, mkey_ptr,
+    if ((errcode = krb5_dbe_decrypt_key_data(kdc_context, NULL,
                                              client_key, &client_keyblock,
                                              NULL))) {
         status = "DECRYPT_CLIENT_KEY";
diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c
index 2c4514c..b424b3e 100644
--- a/src/kdc/do_tgs_req.c
+++ b/src/kdc/do_tgs_req.c
@@ -104,7 +104,6 @@ process_tgs_req(krb5_data *pkt, const krb5_fulladdr *from,
     krb5_keyblock session_key;
     krb5_timestamp rtime;
     krb5_keyblock *reply_key = NULL;
-    krb5_keyblock *mkey_ptr;
     krb5_key_data  *server_key;
     char *cname = 0, *sname = 0, *altcname = 0;
     krb5_last_req_entry *nolrarray[2], nolrentry;
@@ -625,31 +624,11 @@ tgt_again:
             goto cleanup;
         }
 
-        if ((errcode = krb5_dbe_find_mkey(kdc_context, master_keylist, server,
-                                          &mkey_ptr))) {
-            krb5_keylist_node *tmp_mkey_list;
-            /* try refreshing master key list */
-            /* XXX it would nice if we had the mkvno here for optimization */
-            if (krb5_db_fetch_mkey_list(kdc_context, master_princ,
-                                        &master_keyblock, 0, &tmp_mkey_list) == 0) {
-                krb5_dbe_free_key_list(kdc_context, master_keylist);
-                master_keylist = tmp_mkey_list;
-                if ((errcode = krb5_dbe_find_mkey(kdc_context, master_keylist,
-                                                  server, &mkey_ptr))) {
-                    status = "FINDING_MASTER_KEY";
-                    goto cleanup;
-                }
-            } else {
-                status = "FINDING_MASTER_KEY";
-                goto cleanup;
-            }
-        }
-
         /*
          * Convert server.key into a real key
          * (it may be encrypted in the database)
          */
-        if ((errcode = krb5_dbe_decrypt_key_data(kdc_context, mkey_ptr,
+        if ((errcode = krb5_dbe_decrypt_key_data(kdc_context, NULL,
                                                  server_key, &encrypting_key,
                                                  NULL))) {
             status = "DECRYPT_SERVER_KEY";
diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c
index 4c413d0..503c231 100644
--- a/src/kdc/kdc_preauth.c
+++ b/src/kdc/kdc_preauth.c
@@ -711,7 +711,7 @@ get_entry_data(krb5_context context,
     int i, k;
     krb5_data *ret;
     krb5_deltat *delta;
-    krb5_keyblock *keys, *mkey_ptr;
+    krb5_keyblock *keys;
     krb5_key_data *entry_key;
     krb5_error_code error;
     struct kdc_request_state *state = request->kdc_state;
@@ -748,32 +748,13 @@ get_entry_data(krb5_context context,
         ret->data = (char *) keys;
         ret->length = sizeof(krb5_keyblock) * (request->nktypes + 1);
         memset(ret->data, 0, ret->length);
-        if ((error = krb5_dbe_find_mkey(context, master_keylist, entry,
-                                        &mkey_ptr))) {
-            krb5_keylist_node *tmp_mkey_list;
-            /* try refreshing the mkey list in case it's been updated */
-            if (krb5_db_fetch_mkey_list(context, master_princ,
-                                        &master_keyblock, 0,
-                                        &tmp_mkey_list) == 0) {
-                krb5_dbe_free_key_list(context, master_keylist);
-                master_keylist = tmp_mkey_list;
-                if ((error = krb5_dbe_find_mkey(context, master_keylist, entry,
-                                                &mkey_ptr))) {
-                    free(ret);
-                    return (error);
-                }
-            } else {
-                free(ret);
-                return (error);
-            }
-        }
         k = 0;
         for (i = 0; i < request->nktypes; i++) {
             entry_key = NULL;
             if (krb5_dbe_find_enctype(context, entry, request->ktype[i],
                                       -1, 0, &entry_key) != 0)
                 continue;
-            if (krb5_dbe_decrypt_key_data(context, mkey_ptr, entry_key,
+            if (krb5_dbe_decrypt_key_data(context, NULL, entry_key,
                                           &keys[k], NULL) != 0) {
                 if (keys[k].contents != NULL)
                     krb5_free_keyblock_contents(context, &keys[k]);
@@ -1328,7 +1309,7 @@ return_padata(krb5_context context, krb5_db_entry *client, krb5_data *req_pkt,
     }
     key_modified = FALSE;
     null_item.contents = NULL;
-    null_item.length = NULL;
+    null_item.length = 0;
     send_pa = send_pa_list;
     *send_pa = 0;
 
@@ -1430,7 +1411,7 @@ verify_enc_timestamp(krb5_context context, krb5_db_entry *client,
     krb5_data                   scratch;
     krb5_data                   enc_ts_data;
     krb5_enc_data               *enc_data = 0;
-    krb5_keyblock               key, *mkey_ptr;
+    krb5_keyblock               key;
     krb5_key_data *             client_key;
     krb5_int32                  start;
     krb5_timestamp              timenow;
@@ -1448,24 +1429,6 @@ verify_enc_timestamp(krb5_context context, krb5_db_entry *client,
     if ((enc_ts_data.data = (char *) malloc(enc_ts_data.length)) == NULL)
         goto cleanup;
 
-    if ((retval = krb5_dbe_find_mkey(context, master_keylist, client,
-                                     &mkey_ptr))) {
-        krb5_keylist_node *tmp_mkey_list;
-        /* try refreshing the mkey list in case it's been updated */
-        if (krb5_db_fetch_mkey_list(context, master_princ,
-                                    &master_keyblock, 0,
-                                    &tmp_mkey_list) == 0) {
-            krb5_dbe_free_key_list(context, master_keylist);
-            master_keylist = tmp_mkey_list;
-            if ((retval = krb5_dbe_find_mkey(context, master_keylist, client,
-                                             &mkey_ptr))) {
-                goto cleanup;
-            }
-        } else {
-            goto cleanup;
-        }
-    }
-
     start = 0;
     decrypt_err = 0;
     while (1) {
@@ -1474,7 +1437,7 @@ verify_enc_timestamp(krb5_context context, krb5_db_entry *client,
                                               -1, 0, &client_key)))
             goto cleanup;
 
-        if ((retval = krb5_dbe_decrypt_key_data(context, mkey_ptr, client_key,
+        if ((retval = krb5_dbe_decrypt_key_data(context, NULL, client_key,
                                                 &key, NULL)))
             goto cleanup;
 
@@ -2785,22 +2748,6 @@ static krb5_error_code verify_pkinit_request(
         goto cleanup;
     }
     cert_hash_len = strlen(cert_hash);
-    if ((krtn = krb5_dbe_find_mkey(context, master_keylist, &entry, &mkey_ptr))) {
-        krb5_keylist_node *tmp_mkey_list;
-        /* try refreshing the mkey list in case it's been updated */
-        if (krb5_db_fetch_mkey_list(context, master_princ,
-                                    &master_keyblock, 0,
-                                    &tmp_mkey_list) == 0) {
-            krb5_dbe_free_key_list(context, master_keylist);
-            master_keylist = tmp_mkey_list;
-            if ((krtn = krb5_dbe_find_mkey(context, master_keylist, &entry,
-                                           &mkey_ptr))) {
-                goto cleanup;
-            }
-        } else {
-            goto cleanup;
-        }
-    }
     for(key_dex=0; key_dex<client->n_key_data; key_dex++) {
         krb5_key_data *key_data = &client->key_data[key_dex];
         kdcPkinitDebug("--- key %u type[0] %u length[0] %u type[1] %u length[1] %u\n",
@@ -2815,7 +2762,7 @@ static krb5_error_code verify_pkinit_request(
          * Unfortunately this key is stored encrypted even though it's
          * not sensitive...
          */
-        krtn = krb5_dbe_decrypt_key_data(context, mkey_ptr, key_data,
+        krtn = krb5_dbe_decrypt_key_data(context, NULL, key_data,
                                          &decrypted_key, NULL);
         if(krtn) {
             kdcPkinitDebug("verify_pkinit_request: error decrypting cert hash block\n");
diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
index 61bd7fd..7b62b53 100644
--- a/src/kdc/kdc_util.c
+++ b/src/kdc/kdc_util.c
@@ -454,7 +454,6 @@ kdc_get_server_key(krb5_ticket *ticket, unsigned int flags,
     krb5_error_code       retval;
     krb5_boolean          similar;
     krb5_key_data       * server_key;
-    krb5_keyblock       * mkey_ptr;
     krb5_db_entry       * server = NULL;
 
     *server_ptr = NULL;
@@ -478,27 +477,6 @@ kdc_get_server_key(krb5_ticket *ticket, unsigned int flags,
         goto errout;
     }
 
-    if ((retval = krb5_dbe_find_mkey(kdc_context, master_keylist, server,
-                                     &mkey_ptr))) {
-        krb5_keylist_node *tmp_mkey_list;
-        /* try refreshing master key list */
-        /* XXX it would nice if we had the mkvno here for optimization */
-        if (krb5_db_fetch_mkey_list(kdc_context, master_princ,
-                                    &master_keyblock, 0, &tmp_mkey_list) == 0) {
-            krb5_dbe_free_key_list(kdc_context, master_keylist);
-            master_keylist = tmp_mkey_list;
-            retval = krb5_db_set_mkey_list(kdc_context, master_keylist);
-            if (retval)
-                goto errout;
-            if ((retval = krb5_dbe_find_mkey(kdc_context, master_keylist,
-                                             server, &mkey_ptr))) {
-                goto errout;
-            }
-        } else {
-            goto errout;
-        }
-    }
-
     retval = krb5_dbe_find_enctype(kdc_context, server,
                                    match_enctype ? ticket->enc_part.enctype : -1,
                                    -1, (krb5_int32)ticket->enc_part.kvno,
@@ -510,7 +488,7 @@ kdc_get_server_key(krb5_ticket *ticket, unsigned int flags,
         goto errout;
     }
     if ((*key = (krb5_keyblock *)malloc(sizeof **key))) {
-        retval = krb5_dbe_decrypt_key_data(kdc_context, mkey_ptr, server_key,
+        retval = krb5_dbe_decrypt_key_data(kdc_context, NULL, server_key,
                                            *key, NULL);
     } else
         retval = ENOMEM;
diff --git a/src/kdc/main.c b/src/kdc/main.c
index 60a3dc0..21c67f8 100644
--- a/src/kdc/main.c
+++ b/src/kdc/main.c
@@ -431,12 +431,6 @@ init_realm(kdc_realm_t *rdp, char *realm, char *def_mpname,
         goto whoops;
     }
 
-    kret = krb5_db_set_mkey_list(rdp->realm_context, rdp->mkey_list);
-    if (kret) {
-        kdc_err(rdp->realm_context, kret,
-                "while setting master key list for realm %s", realm);
-        goto whoops;
-    }
 
     /* Set up the keytab */
     if ((kret = krb5_ktkdb_resolve(rdp->realm_context, NULL,
diff --git a/src/lib/kadm5/srv/svr_principal.c b/src/lib/kadm5/srv/svr_principal.c
index dc16406..c65c169 100644
--- a/src/lib/kadm5/srv/svr_principal.c
+++ b/src/lib/kadm5/srv/svr_principal.c
@@ -38,7 +38,7 @@ extern  krb5_keylist_node  *master_keylist;
 extern  krb5_actkvno_node  *active_mkey_list;
 extern  krb5_db_entry       master_db;
 
-static int decrypt_key_data(krb5_context context, krb5_keyblock *mkey,
+static int decrypt_key_data(krb5_context context,
                             int n_key_data, krb5_key_data *key_data,
                             krb5_keyblock **keyblocks, int *n_keys);
 
@@ -933,17 +933,16 @@ done:
  */
 static kadm5_ret_t
 check_pw_reuse(krb5_context context,
-               krb5_keyblock *mkey,
                krb5_keyblock *hist_keyblock,
                int n_new_key_data, krb5_key_data *new_key_data,
                unsigned int n_pw_hist_data, osa_pw_hist_ent *pw_hist_data)
 {
-    int x, y, z;
+    unsigned int x, y, z;
     krb5_keyblock newkey, histkey;
     krb5_error_code ret;
 
     for (x = 0; x < n_new_key_data; x++) {
-        ret = krb5_dbe_decrypt_key_data(context, mkey, &(new_key_data[x]),
+        ret = krb5_dbe_decrypt_key_data(context, NULL, &(new_key_data[x]),
                                         &newkey, NULL);
         if (ret)
             return(ret);
@@ -996,7 +995,7 @@ check_pw_reuse(krb5_context context,
  * set to n_key_data.
  */
 static
-int create_history_entry(krb5_context context, krb5_keyblock *mkey,
+int create_history_entry(krb5_context context,
                          krb5_keyblock *hist_key, int n_key_data,
                          krb5_key_data *key_data, osa_pw_hist_ent *hist)
 {
@@ -1010,7 +1009,7 @@ int create_history_entry(krb5_context context, krb5_keyblock *mkey,
     memset(hist->key_data, 0, n_key_data*sizeof(krb5_key_data));
 
     for (i = 0; i < n_key_data; i++) {
-        ret = krb5_dbe_decrypt_key_data(context, mkey, &key_data[i], &key,
+        ret = krb5_dbe_decrypt_key_data(context, NULL, &key_data[i], &key,
                                         &salt);
         if (ret)
             return ret;
@@ -1394,13 +1393,13 @@ kadm5_chpass_principal_3(void *server_handle,
             goto done;
 
         ret = create_history_entry(handle->context,
-                                   act_mkey, &hist_keyblock,
+                                   &hist_keyblock,
                                    kdb_save->n_key_data,
                                    kdb_save->key_data, &hist);
         if (ret)
             goto done;
 
-        ret = check_pw_reuse(handle->context, act_mkey, &hist_keyblock,
+        ret = check_pw_reuse(handle->context, &hist_keyblock,
                              kdb->n_key_data, kdb->key_data,
                              1, &hist);
         if (ret)
@@ -1410,7 +1409,7 @@ kadm5_chpass_principal_3(void *server_handle,
             /* If hist_kvno has changed since the last password change, we
              * can't check the history. */
             if (adb.admin_history_kvno == hist_kvno) {
-                ret = check_pw_reuse(handle->context, act_mkey, &hist_keyblock,
+                ret = check_pw_reuse(handle->context, &hist_keyblock,
                                      kdb->n_key_data, kdb->key_data,
                                      adb.old_key_len, adb.old_keys);
                 if (ret)
@@ -1598,7 +1597,7 @@ kadm5_randkey_principal_3(void *server_handle,
     kdb->fail_auth_count = 0;
 
     if (keyblocks) {
-        ret = decrypt_key_data(handle->context, act_mkey,
+        ret = decrypt_key_data(handle->context,
                                kdb->n_key_data, kdb->key_data,
                                keyblocks, n_keys);
         if (ret)
@@ -2007,7 +2006,6 @@ kadm5_get_principal_keys(void *server_handle /* IN */,
     osa_princ_ent_rec           adb;
     kadm5_ret_t                 ret;
     kadm5_server_handle_t       handle = server_handle;
-    krb5_keyblock               *mkey_ptr;
 
     if (keyblocks)
         *keyblocks = NULL;
@@ -2021,26 +2019,7 @@ kadm5_get_principal_keys(void *server_handle /* IN */,
         return(ret);
 
     if (keyblocks) {
-        if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist, kdb,
-                                      &mkey_ptr))) {
-            krb5_keylist_node *tmp_mkey_list;
-            /* try refreshing master key list */
-            /* XXX it would nice if we had the mkvno here for optimization */
-            if (krb5_db_fetch_mkey_list(handle->context, master_princ,
-                                        &master_keyblock, 0,
-                                        &tmp_mkey_list) == 0) {
-                krb5_dbe_free_key_list(handle->context, master_keylist);
-                master_keylist = tmp_mkey_list;
-                if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist,
-                                              kdb, &mkey_ptr))) {
-                    goto done;
-                }
-            } else {
-                goto done;
-            }
-        }
-
-        ret = decrypt_key_data(handle->context, mkey_ptr,
+        ret = decrypt_key_data(handle->context,
                                kdb->n_key_data, kdb->key_data,
                                keyblocks, n_keys);
         if (ret)
@@ -2057,11 +2036,11 @@ done:
 
 /*
  * Allocate an array of n_key_data krb5_keyblocks, fill in each
- * element with the results of decrypting the nth key in key_data with
- * mkey, and if n_keys is not NULL fill it in with the
+ * element with the results of decrypting the nth key in key_data,
+ * and if n_keys is not NULL fill it in with the
  * number of keys decrypted.
  */
-static int decrypt_key_data(krb5_context context, krb5_keyblock *mkey,
+static int decrypt_key_data(krb5_context context,
                             int n_key_data, krb5_key_data *key_data,
                             krb5_keyblock **keyblocks, int *n_keys)
 {
@@ -2074,7 +2053,7 @@ static int decrypt_key_data(krb5_context context, krb5_keyblock *mkey,
     memset(keys, 0, n_key_data*sizeof(krb5_keyblock));
 
     for (i = 0; i < n_key_data; i++) {
-        ret = krb5_dbe_decrypt_key_data(context, mkey, &key_data[i], &keys[i],
+        ret = krb5_dbe_decrypt_key_data(context, NULL, &key_data[i], &keys[i],
                                         NULL);
         if (ret) {
             for (; i >= 0; i--) {
@@ -2171,7 +2150,7 @@ kadm5_ret_t kadm5_decrypt_key(void *server_handle,
         }
     }
 
-    if ((ret = krb5_dbe_decrypt_key_data(handle->context, mkey_ptr, key_data,
+    if ((ret = krb5_dbe_decrypt_key_data(handle->context, NULL, key_data,
                                          keyblock, keysalt)))
         return ret;
 
diff --git a/src/lib/kdb/kdb5.c b/src/lib/kdb/kdb5.c
index 9786503..907ddc1 100644
--- a/src/lib/kdb/kdb5.c
+++ b/src/lib/kdb/kdb5.c
@@ -1,6 +1,6 @@
 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 /*
- * Copyright 2006, 2009 by the Massachusetts Institute of Technology.
+ * Copyright 2006, 2009, 2010 by the Massachusetts Institute of Technology.
  * All Rights Reserved.
  *
  * Export of this software from the United States of America may
@@ -549,17 +549,22 @@ static krb5_error_code
 kdb_free_lib_handle(krb5_context kcontext)
 {
     krb5_error_code status = 0;
+    krb5_keylist_node *old_keylist = kcontext->dal_handle->master_keylist;
 
     status = kdb_free_library(kcontext->dal_handle->lib_handle);
     if (status)
         return status;
-
+    if (kcontext->dal_handle->free_keylist) {
+        kcontext->dal_handle->master_keylist = NULL; /*force freeing*/
+        krb5_db_free_mkey_list(kcontext, old_keylist);
+    }
+    krb5_free_principal(kcontext, kcontext->dal_handle->master_princ);
     free(kcontext->dal_handle);
     kcontext->dal_handle = NULL;
     return 0;
 }
 
-static krb5_error_code
+static  krb5_error_code
 get_vftabl(krb5_context kcontext, kdb_vftabl **vftabl_ptr)
 {
     krb5_error_code status;
@@ -989,35 +994,6 @@ krb5_db_iterate(krb5_context kcontext,
 }
 
 krb5_error_code
-krb5_db_set_mkey_list(krb5_context kcontext,
-                      krb5_keylist_node * keylist)
-{
-    krb5_error_code status = 0;
-    kdb_vftabl *v;
-
-    status = get_vftabl(kcontext, &v);
-    if (status)
-        return status;
-    if (v->set_master_key_list == NULL)
-        return KRB5_PLUGIN_OP_NOTSUPP;
-    return v->set_master_key_list(kcontext, keylist);
-}
-
-krb5_error_code
-krb5_db_get_mkey_list(krb5_context kcontext, krb5_keylist_node ** keylist)
-{
-    krb5_error_code status = 0;
-    kdb_vftabl *v;
-
-    status = get_vftabl(kcontext, &v);
-    if (status)
-        return status;
-    if (v->get_master_key_list == NULL)
-        return KRB5_PLUGIN_OP_NOTSUPP;
-    return v->get_master_key_list(kcontext, keylist);
-}
-
-krb5_error_code
 krb5_db_fetch_mkey_list(krb5_context     context,
                         krb5_principal        mname,
                         const krb5_keyblock * mkey,
@@ -1026,11 +1002,27 @@ krb5_db_fetch_mkey_list(krb5_context     context,
 {
     kdb_vftabl *v;
     krb5_error_code status = 0;
+    krb5_keylist_node *local_keylist;
 
     status = get_vftabl(context, &v);
     if (status)
         return status;
-    return v->fetch_master_key_list(context, mname, mkey, mkvno, mkey_list);
+    if (!context->dal_handle->master_princ) {
+        status = krb5_copy_principal(context, mname, &context->dal_handle->master_princ);
+        if (status)
+            return status;
+    }
+    if (mkey_list == NULL)
+        mkey_list = &local_keylist;
+    status =  v->fetch_master_key_list(context, mname, mkey, mkvno, mkey_list);
+    if (status == 0) {
+        krb5_keylist_node *old_keylist = context->dal_handle->master_keylist;
+        context->dal_handle->master_keylist = *mkey_list;
+        if (context->dal_handle->free_keylist)
+            krb5_db_free_mkey_list(context, old_keylist);
+        context->dal_handle->free_keylist = (mkey_list == &local_keylist);
+    }
+    return status;
 }
 
 void
@@ -1038,7 +1030,11 @@ krb5_db_free_mkey_list(krb5_context    context,
                        krb5_keylist_node  *mkey_list)
 {
     krb5_keylist_node *cur, *prev;
-
+    
+    if (context&& context->dal_handle->master_keylist == mkey_list) {
+        context->dal_handle->free_keylist = 1;
+        return;
+    }
     for (cur = mkey_list; cur != NULL;) {
         prev = cur;
         cur = cur->next;
@@ -2176,7 +2172,6 @@ krb5_db_promote(krb5_context kcontext, char **db_args)
     free(section);
     return status;
 }
-
 krb5_error_code
 krb5_dbe_decrypt_key_data( krb5_context         kcontext,
                            const krb5_keyblock        * mkey,
@@ -2184,13 +2179,44 @@ krb5_dbe_decrypt_key_data( krb5_context         kcontext,
                            krb5_keyblock      * dbkey,
                            krb5_keysalt       * keysalt)
 {
-    krb5_error_code status = 0;
+    krb5_error_code status = 0, status2=0;
     kdb_vftabl *v;
-
+    krb5_keylist_node *n = kcontext->dal_handle->master_keylist;
+    const char *msg = NULL;
+    krb5_boolean first_pass = 1;
     status = get_vftabl(kcontext, &v);
     if (status)
         return status;
-    return v->decrypt_key_data(kcontext, mkey, key_data, dbkey, keysalt);
+    if (mkey ||!n)
+        return v->decrypt_key_data(kcontext, mkey, key_data, dbkey, keysalt);
+again: for (;n; n = n->next) {
+        krb5_clear_error_message(kcontext);
+        status2 = v->decrypt_key_data(kcontext, &n->keyblock, key_data, dbkey, keysalt);
+        if (status2 == 0) {
+            status = 0;
+            goto cleanup;
+        }
+        if (status == 0) {
+            status = status2;
+            msg = krb5_get_error_message(kcontext, status);
+        }
+    }
+    if (first_pass&&kcontext->dal_handle->master_keylist) {
+        /* Try reloading master keys*/
+        krb5_keyblock *cur_mkey = &kcontext->dal_handle->master_keylist->keyblock;
+        if (krb5_db_fetch_mkey_list(kcontext, kcontext->dal_handle->master_princ,
+                                    cur_mkey, -1, NULL) == 0) {
+            first_pass = 0;
+            goto again;
+        }
+    }
+    cleanup:
+        if (msg) {
+            krb5_set_error_message(kcontext, status, msg);
+            krb5_free_error_message(kcontext, msg);
+        }
+        return status;
+
 }
 
 krb5_error_code
diff --git a/src/lib/kdb/kdb5.h b/src/lib/kdb/kdb5.h
index c1265e7..6d5c0a6 100644
--- a/src/lib/kdb/kdb5.h
+++ b/src/lib/kdb/kdb5.h
@@ -30,6 +30,9 @@ struct _kdb5_dal_handle
        extent.  */
     void *db_context;
     db_library lib_handle;
+    krb5_keylist_node *master_keylist;
+    krb5_boolean free_keylist;
+    krb5_principal master_princ;
 };
 /* typedef kdb5_dal_handle is in k5-int.h now */
 
diff --git a/src/lib/kdb/keytab.c b/src/lib/kdb/keytab.c
index 4d56915..dbbbe75 100644
--- a/src/lib/kdb/keytab.c
+++ b/src/lib/kdb/keytab.c
@@ -124,8 +124,6 @@ krb5_ktkdb_get_entry(in_context, id, principal, kvno, enctype, entry)
     krb5_keytab_entry   * entry;
 {
     krb5_context          context;
-    krb5_keylist_node  * master_keylist;
-    krb5_keyblock       * master_key;
     krb5_error_code       kerror = 0;
     krb5_key_data       * key_data;
     krb5_db_entry       * db_entry;
@@ -157,14 +155,6 @@ krb5_ktkdb_get_entry(in_context, id, principal, kvno, enctype, entry)
     }
 
     /* match key */
-    kerror = krb5_db_get_mkey_list(context, &master_keylist);
-    if (kerror)
-        goto error;
-
-    kerror = krb5_dbe_find_mkey(context, master_keylist, db_entry, &master_key);
-    if (kerror)
-        goto error;
-
     /* For cross realm tgts, we match whatever enctype is provided;
      * for other principals, we only match the first enctype that is
      * found.  Since the TGS and AS code do the same thing, then we
@@ -178,7 +168,7 @@ krb5_ktkdb_get_entry(in_context, id, principal, kvno, enctype, entry)
         goto error;
 
 
-    kerror = krb5_dbe_decrypt_key_data(context, master_key, key_data,
+    kerror = krb5_dbe_decrypt_key_data(context, NULL, key_data,
                                        &entry->key, NULL);
     if (kerror)
         goto error;
diff --git a/src/lib/kdb/libkdb5.exports b/src/lib/kdb/libkdb5.exports
index 6e89047..f3f6a80 100644
--- a/src/lib/kdb/libkdb5.exports
+++ b/src/lib/kdb/libkdb5.exports
@@ -18,7 +18,6 @@ krb5_db_fini
 krb5_db_free_principal
 krb5_db_get_age
 krb5_db_get_key_data_kvno
-krb5_db_get_mkey_list
 krb5_db_get_context
 krb5_db_get_principal
 krb5_db_iterate
@@ -26,7 +25,6 @@ krb5_db_lock
 krb5_db_put_principal
 krb5_db_refresh_config
 krb5_db_set_context
-krb5_db_set_mkey_list
 krb5_db_setup_mkey_name
 krb5_db_sign_authdata
 krb5_db_unlock
diff --git a/src/tests/verify/kdb5_verify.c b/src/tests/verify/kdb5_verify.c
index 4f77b19..a19a5aa 100644
--- a/src/tests/verify/kdb5_verify.c
+++ b/src/tests/verify/kdb5_verify.c
@@ -272,7 +272,7 @@ check_princ(context, str_princ)
     }
     krb5_free_principal(context, princ);
 
-    if ((retval = krb5_dbe_decrypt_key_data(context, &master_keyblock,
+    if ((retval = krb5_dbe_decrypt_key_data(context, NULL,
                                             kdbe->key_data, &db_key, NULL))) {
         com_err(progname, retval, "while decrypting key for '%s'", princ_name);
         goto errout;
-- 
1.7.1




More information about the krbdev mailing list