]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Implemented kdb5_util purge_meys
authorWill Fiveash <will.fiveash@oracle.com>
Fri, 30 Jan 2009 20:07:37 +0000 (20:07 +0000)
committerWill Fiveash <will.fiveash@oracle.com>
Fri, 30 Jan 2009 20:07:37 +0000 (20:07 +0000)
Fixed a number of memleaks where the master key list was refetched.

Modified the initial actkvno TL entry to set the act_time to 0 in case
the kdc's clock is moved back after the initial entry is created.  This
way the initial mkey will always be active.

git-svn-id: svn://anonsvn.mit.edu/krb5/branches/mkey_migrate@21836 dc483132-0cff-0310-8789-dd5450dbe970

14 files changed:
src/include/kdb.h
src/kadmin/dbutil/kdb5_create.c
src/kadmin/dbutil/kdb5_mkey.c
src/kadmin/dbutil/kdb5_util.c
src/kadmin/dbutil/kdb5_util.h
src/kdc/do_as_req.c
src/kdc/do_tgs_req.c
src/kdc/kdc_preauth.c
src/kdc/kdc_util.c
src/lib/kadm5/srv/svr_principal.c
src/lib/kdb/kdb5.c
src/lib/krb5/error_tables/kdb5_err.et
src/plugins/kdb/db2/db2_exp.c
src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c

index bcf0bee57066a2c39a021fdce74407283e6ac885..240ac0fd523b6f4aaa90e06ff6d2cbbb2aec3a9e 100644 (file)
@@ -483,6 +483,11 @@ krb5_dbe_lookup_last_pwd_change( krb5_context          context,
                                 krb5_db_entry       * entry,
                                 krb5_timestamp      * stamp);
 
+krb5_error_code
+krb5_dbe_delete_tl_data( krb5_context    context,
+                         krb5_db_entry * entry,
+                         krb5_int16      tl_data_type);
+
 krb5_error_code
 krb5_dbe_update_tl_data( krb5_context          context,
                         krb5_db_entry       * entry,
@@ -682,6 +687,9 @@ krb5_dbe_free_actkvno_list(krb5_context, krb5_actkvno_node *);
 void
 krb5_dbe_free_mkey_aux_list(krb5_context, krb5_mkey_aux_node *);
 
+void
+krb5_dbe_free_tl_data(krb5_context, krb5_tl_data *);
+
 #define KRB5_KDB_DEF_FLAGS     0
 
 #define KDB_MAX_DB_NAME                        128
index ebf07b490a165e744c44b6068c036f43ddebe662..6a638a35122d32985e4476d7a48aae1f29caae3e 100644 (file)
@@ -467,7 +467,8 @@ add_principal(context, princ, op, pblock)
          */
         actkvno.next = NULL;
         actkvno.act_kvno = mkey_kvno;
-        actkvno.act_time = now;
+        /* earliest possible time in case system clock is set back */
+        actkvno.act_time = 0;
         if ((retval = krb5_dbe_update_actkvno(context, &entry, &actkvno)))
             return retval;
 
index 1be680005b4c35d38429807169c3e676d6236f6a..53c0102f43510eea4510b372bbfae8917f5dbc51 100644 (file)
@@ -30,6 +30,7 @@
 #endif
 
 extern krb5_keyblock master_keyblock; /* current mkey */
+extern krb5_kvno   master_kvno;
 extern krb5_principal master_princ;
 extern krb5_keylist_node *master_keylist;
 extern krb5_data master_salt;
@@ -110,7 +111,7 @@ add_new_mkey(krb5_context context, krb5_db_entry *master_entry,
                                               &master_entry->key_data[0]))) {
         return (retval);
     }
-    /* so getprinc will show the new mkvno */
+    /* the mvkno should be that of the newest mkey */
     if ((retval = krb5_dbe_update_mkvno(context, master_entry, new_mkey_kvno))) {
         krb5_free_key_data_contents(context, &master_entry->key_data[0]);
         return (retval);
@@ -501,7 +502,7 @@ kdb5_use_mkey(int argc, char *argv[])
 
             if (cur_actkvno->act_kvno == use_kvno) {
                 cur_actkvno->act_time = start_time;
-                inserted = 1;   /* fake it */
+                inserted = TRUE;   /* fake it */
             }
             if (!inserted) {
                 if (new_actkvno->act_time < cur_actkvno->act_time) {
@@ -941,7 +942,8 @@ kdb5_update_princ_encryption(int argc, char *argv[])
     krb5_error_code retval;
     krb5_actkvno_node *actkvno_list;
     krb5_db_entry master_entry;
-    int nentries = 1, more = 0;
+    int nentries = 1;
+    krb5_boolean more = FALSE;
     char *mkey_fullname = 0;
 #ifdef BSD_REGEXPS
     char *msg;
@@ -1092,3 +1094,327 @@ cleanup:
     krb5_free_keyblock(util_context, tmp_keyblock);
     krb5_free_unparsed_name(util_context, mkey_fullname);
 }
+
+struct kvnos_in_use {
+    krb5_kvno               kvno;
+    unsigned int            use_count;
+};
+
+struct purge_args {
+    krb5_context         kcontext;
+    struct kvnos_in_use  *kvnos;
+    unsigned int         num_kvnos;
+};
+
+static krb5_error_code
+find_mkvnos_in_use(krb5_pointer   ptr,
+                   krb5_db_entry *entry)
+{
+    krb5_error_code retval;
+    struct purge_args * args;
+    unsigned int i;
+    krb5_kvno mkvno;
+
+    args = (struct purge_args *) ptr;
+
+    retval = krb5_dbe_lookup_mkvno(args->kcontext, entry, &mkvno);
+    if (retval)
+        return (retval);
+
+    for (i = 0; i < args->num_kvnos; i++) {
+        if (args->kvnos[i].kvno == mkvno) {
+            /* XXX do I need to worry about use_count wrapping? */
+            args->kvnos[i].use_count++;
+            break;
+        }
+    }
+    return 0;
+}
+
+void
+kdb5_purge_mkeys(int argc, char *argv[])
+{
+    int optchar;
+    krb5_error_code retval;
+    char  *mkey_fullname;
+    krb5_timestamp now;
+    krb5_db_entry master_entry;
+    int   nentries = 0;
+    krb5_boolean more = FALSE;
+    krb5_boolean force = FALSE, dry_run = FALSE, verbose = FALSE;
+    struct purge_args args;
+    char buf[5];
+    unsigned int i, j, k, num_kvnos_inuse, num_kvnos_purged;
+    unsigned int old_key_data_count;
+    krb5_actkvno_node *cur_actkvno_list, *actkvno_entry, *prev_actkvno_entry;
+    krb5_mkey_aux_node *cur_mkey_aux_list, *mkey_aux_entry, *prev_mkey_aux_entry;
+    krb5_key_data *old_key_data;
+
+    optind = 1;
+    while ((optchar = getopt(argc, argv, "fnv")) != -1) {
+        switch(optchar) {
+        case 'f':
+            force = TRUE;
+            break;
+        case 'n':
+            dry_run = TRUE; /* mkey princ will not be modified */
+            force = TRUE; /* implied */
+            break;
+        case 'v':
+            verbose = TRUE;
+            break;
+        case '?':
+        default:
+            usage();
+            return;
+        }
+    }
+
+    /* assemble & parse the master key name */
+    if ((retval = krb5_db_setup_mkey_name(util_context,
+                                          global_params.mkey_name,
+                                          global_params.realm,  
+                                          &mkey_fullname, &master_princ))) {
+        com_err(progname, retval, "while setting up master key name");
+        exit_status++;
+        return;
+    }
+
+    retval = krb5_db_get_principal(util_context, master_princ, &master_entry,
+                                   &nentries, &more);
+    if (retval != 0) {
+        com_err(progname, retval,
+                "while getting master key principal %s",
+                mkey_fullname);
+        exit_status++;
+        return;
+    } else if (nentries == 0) {
+        com_err(progname, KRB5_KDB_NOENTRY,
+                "principal %s not found in Kerberos database",
+                mkey_fullname);
+        exit_status++;
+        return;
+    } else if (nentries > 1) {
+        com_err(progname, KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE,
+                "principal %s has multiple entries in Kerberos database",
+                mkey_fullname);
+        exit_status++;
+        return;
+    }
+
+    if (!force) {
+        printf("Will purge/delete all unused master keys stored in the '%s' principal, are you sure?\n",
+               mkey_fullname);
+        printf("(type 'yes' to confirm)? ");
+        if (fgets(buf, sizeof(buf), stdin) == NULL) {
+            exit_status++;
+            return;
+        }
+        if (strcmp(buf, "yes\n")) {
+            exit_status++;
+            return;
+        }
+        printf("OK, purging unused master keys from '%s'...\n", mkey_fullname);
+    }
+
+    /* save the old keydata */
+    old_key_data_count = master_entry.n_key_data;
+    if (old_key_data_count == 1) {
+        if (verbose)
+            printf("There is only one master key which can not be purged.\n");
+        return;
+    }
+    old_key_data = master_entry.key_data;
+
+    args.kvnos = (struct kvnos_in_use *) malloc(sizeof(struct kvnos_in_use) * old_key_data_count);
+    if (args.kvnos == NULL) {
+        retval = ENOMEM;
+        com_err(progname, ENOMEM, "while allocating args.kvnos");
+        exit_status++;
+        return;
+    }
+    memset(args.kvnos, 0, sizeof(struct kvnos_in_use) * old_key_data_count);
+    args.num_kvnos = old_key_data_count;
+    args.kcontext = util_context;
+
+    /* populate the kvnos array with all the current mkvnos */
+    for (i = 0; i < old_key_data_count; i++)
+        args.kvnos[i].kvno =  master_entry.key_data[i].key_data_kvno;
+
+    if ((retval = krb5_db_iterate(util_context,
+                                  NULL,
+                                  find_mkvnos_in_use,
+                                  (krb5_pointer) &args))) {
+        com_err(progname, retval, "while finding master keys in use");
+        exit_status++;
+        return;
+    }
+    /*
+     * args.kvnos has been marked with the mkvno's that are currently protecting
+     * princ entries
+     */
+    if (verbose) {
+        if (dry_run)
+            printf("Would purge the follwing master key(s) from %s:\n", mkey_fullname);
+        else
+            printf("Will purge the follwing master key(s) from %s:\n", mkey_fullname);
+    }
+
+    /* find # of keys still in use or print out verbose info */
+    for (i = num_kvnos_inuse = num_kvnos_purged = 0; i < args.num_kvnos; i++) {
+        if (args.kvnos[i].use_count > 0) {
+            num_kvnos_inuse++;
+        } else {
+            /* this key would be deleted */
+            if (args.kvnos[i].kvno == master_kvno) {
+                com_err(progname, KRB5_KDB_STORED_MKEY_NOTCURRENT,
+                        "master key stash file needs updating");
+                exit_status++;
+                return;
+            }
+            num_kvnos_purged++;
+            if (verbose)
+                printf("KNVO: %d\n", args.kvnos[i].kvno);
+        }
+    }
+    /* didn't find any keys to purge */
+    if (num_kvnos_inuse == args.num_kvnos) {
+        if (verbose)
+            printf("No keys will be purged\n");
+        goto clean_and_exit;
+    }
+    if (dry_run) {
+        /* bail before doing anything else */
+        printf("%d key(s) would be purged\n", num_kvnos_purged);
+        goto clean_and_exit;
+    }
+
+    retval = krb5_dbe_lookup_actkvno(util_context, &master_entry, &cur_actkvno_list);
+    if (retval != 0) {
+        com_err(progname, retval, "while looking up active kvno list");
+        exit_status++;
+        return;
+    }
+
+    retval = krb5_dbe_lookup_mkey_aux(util_context, &master_entry, &cur_mkey_aux_list);
+    if (retval != 0) {
+        com_err(progname, retval, "while looking up mkey aux data list");
+        exit_status++;
+        return;
+    }
+
+    master_entry.key_data = (krb5_key_data *) malloc(sizeof(krb5_key_data) * num_kvnos_inuse);
+    if (master_entry.key_data == NULL) {
+        retval = ENOMEM;
+        com_err(progname, ENOMEM, "while allocating key_data");
+        exit_status++;
+        return;
+    }
+    memset((char *) master_entry.key_data, 0, sizeof(krb5_key_data) * num_kvnos_inuse);
+    master_entry.n_key_data = num_kvnos_inuse; /* there's only 1 mkey per kvno */
+
+    /*
+     * Assuming that the latest mkey will not be purged because it will always
+     * be "in use" so this code will not bother with encrypting keys again.
+     */
+    for (i = k = 0; i < old_key_data_count; i++) {
+        for (j = 0; j < args.num_kvnos; j++) {
+            if (args.kvnos[j].kvno == (krb5_kvno) old_key_data[i].key_data_kvno) {
+                if (args.kvnos[j].use_count != 0) {
+                    master_entry.key_data[k++] = old_key_data[i];
+                    break;
+                } else {
+                    /* remove unused mkey */
+                    /* adjust the actkno data */
+                    for (prev_actkvno_entry = actkvno_entry = cur_actkvno_list;
+                         actkvno_entry != NULL;
+                         actkvno_entry = actkvno_entry->next) {
+
+                        if (actkvno_entry->act_kvno == args.kvnos[j].kvno) {
+                            if (actkvno_entry == cur_actkvno_list) {
+                                /* remove from head */
+                                cur_actkvno_list = actkvno_entry->next;
+                                prev_actkvno_entry = cur_actkvno_list;
+                            } else if (actkvno_entry->next == NULL) {
+                                /* remove from tail */
+                                prev_actkvno_entry->next = NULL;
+                            } else {
+                                /* remove in between */
+                                prev_actkvno_entry->next = actkvno_entry->next;
+                            }
+                            /* XXX WAF: free actkvno_entry */
+                            break; /* deleted entry, no need to loop further */
+                        } else {
+                            prev_actkvno_entry = actkvno_entry;
+                        }
+                    }
+                    /* adjust the mkey aux data */
+                    for (prev_mkey_aux_entry = mkey_aux_entry = cur_mkey_aux_list;
+                         mkey_aux_entry != NULL;
+                         mkey_aux_entry = mkey_aux_entry->next) {
+
+                        if (mkey_aux_entry->mkey_kvno == args.kvnos[j].kvno) {
+                            if (mkey_aux_entry == cur_mkey_aux_list) {
+                                cur_mkey_aux_list = mkey_aux_entry->next;
+                                prev_mkey_aux_entry = cur_mkey_aux_list;
+                            } else if (mkey_aux_entry->next == NULL) {
+                                prev_mkey_aux_entry->next = NULL;
+                            } else {
+                                prev_mkey_aux_entry->next = mkey_aux_entry->next;
+                            }
+                            /* XXX WAF: free mkey_aux_entry */
+                            break; /* deleted entry, no need to loop further */
+                        } else {
+                            prev_mkey_aux_entry = mkey_aux_entry;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    assert(k == num_kvnos_inuse);
+
+    if ((retval = krb5_dbe_update_actkvno(util_context, &master_entry,
+                                          cur_actkvno_list))) {
+        com_err(progname, retval,
+                "while updating actkvno data for master principal entry");
+        exit_status++;
+        return;
+    }
+
+    if ((retval = krb5_dbe_update_mkey_aux(util_context, &master_entry,
+                                           cur_mkey_aux_list))) {
+        com_err(progname, retval,
+                "while updating mkey_aux data for master principal entry");
+        exit_status++;
+        return;
+    }
+
+    if ((retval = krb5_timeofday(util_context, &now))) {
+        com_err(progname, retval, "while getting current time");
+        exit_status++;
+        return;
+    }
+
+    if ((retval = krb5_dbe_update_mod_princ_data(util_context, &master_entry,
+                                                 now, master_princ))) {
+        com_err(progname, retval,
+                "while updating the master key principal modification time");
+        exit_status++;
+        return;
+    }
+
+    if ((retval = krb5_db_put_principal(util_context, &master_entry, &nentries))) {
+        (void) krb5_db_fini(util_context);
+        com_err(progname, retval, "while adding master key entry to the database");
+        exit_status++;
+        return;
+    }
+
+clean_and_exit:
+    /* clean up */
+    (void) krb5_db_fini(util_context);
+    free(args.kvnos);
+    free(mkey_fullname);
+    return;
+}
index 460160a048e3ac580a269ac31622310bff0c2d1f..6cb70c1cdf933a93f93ea3e63fd173db1f5770d7 100644 (file)
@@ -98,16 +98,18 @@ void usage()
             "\tadd_mkey [-e etype] [-s]\n"
             "\tuse_mkey kvno [time]\n"
             "\tlist_mkeys\n"
-            "\tupdate_princ_encryption [-f] [-n] [-v] [princ-pattern]\n"
              );
      /* avoid a string length compiler warning */
      fprintf(stderr,
+            "\tupdate_princ_encryption [-f] [-n] [-v] [princ-pattern]\n"
+            "\tpurge_mkeys [-f] [-n] [-v]\n"
             "\nwhere,\n\t[-x db_args]* - any number of database specific arguments.\n"
             "\t\t\tLook at each database documentation for supported arguments\n");
      exit(1);
 }
 
 extern krb5_keyblock master_keyblock;
+krb5_kvno   master_kvno; /* fetched */
 extern krb5_keylist_node *master_keylist;
 extern krb5_principal master_princ;
 krb5_db_entry master_entry;
@@ -129,15 +131,16 @@ struct _cmd_table {
      int opendb;
 } cmd_table[] = {
      {"create", kdb5_create, 0},
-     {"destroy", kdb5_destroy, 1},
+     {"destroy", kdb5_destroy, 1}, /* 1 opens the kdb */
      {"stash", kdb5_stash, 1},
      {"dump", dump_db, 1},
      {"load", load_db, 0},
      {"ark", add_random_key, 1},
-     {"add_mkey", kdb5_add_mkey, 1}, /* 1 is opendb */
-     {"use_mkey", kdb5_use_mkey, 1}, /* 1 is opendb */
-     {"list_mkeys", kdb5_list_mkeys, 1}, /* 1 is opendb */
+     {"add_mkey", kdb5_add_mkey, 1},
+     {"use_mkey", kdb5_use_mkey, 1},
+     {"list_mkeys", kdb5_list_mkeys, 1},
      {"update_princ_encryption", kdb5_update_princ_encryption, 1},
+     {"purge_mkeys", kdb5_purge_mkeys, 1},
      {NULL, NULL, 0},
 };
 
@@ -399,7 +402,6 @@ static int open_db_and_mkey()
     int nentries;
     krb5_boolean more;
     krb5_data scratch, pwd, seed;
-    krb5_kvno kvno;
 
     dbactive = FALSE;
     valid_master_key = 0;
@@ -442,9 +444,9 @@ static int open_db_and_mkey()
     }
 
     if (global_params.mask & KADM5_CONFIG_KVNO)
-        kvno = global_params.kvno; /* user specified */
+        master_kvno = global_params.kvno; /* user specified */
     else
-        kvno = IGNORE_VNO;
+        master_kvno = IGNORE_VNO;
 
     /* the databases are now open, and the master principal exists */
     dbactive = TRUE;
@@ -483,7 +485,7 @@ static int open_db_and_mkey()
                                            master_keyblock.enctype,
                                            manual_mkey, FALSE,
                                            global_params.stash_file,
-                                           &kvno,
+                                           &master_kvno,
                                             0, &master_keyblock))) {
             com_err(progname, retval, "while reading master key");
             com_err(progname, 0, "Warning: proceeding without master key");
@@ -494,7 +496,7 @@ static int open_db_and_mkey()
 #if 0 /************** Begin IFDEF'ed OUT *******************************/
     /* krb5_db_fetch_mkey_list will verify the mkey */
     if ((retval = krb5_db_verify_master_key(util_context, master_princ, 
-                                           kvno, &master_keyblock))) {
+                                           master_kvno, &master_keyblock))) {
        com_err(progname, retval, "while verifying master key");
        exit_status++;
        krb5_free_keyblock_contents(util_context, &master_keyblock);
@@ -503,7 +505,8 @@ static int open_db_and_mkey()
 #endif /**************** END IFDEF'ed OUT *******************************/
 
     if ((retval = krb5_db_fetch_mkey_list(util_context, master_princ,
-                                         &master_keyblock, kvno, &master_keylist))) {
+                                         &master_keyblock, master_kvno,
+                                          &master_keylist))) {
        com_err(progname, retval, "while getting master key list");
        com_err(progname, 0, "Warning: proceeding without master key list");
        exit_status++;
index 09290d76d50c965e23f773aac6fffb429caae406..6e99ac3783d810f32cb6c3f2219f06786d37f67b 100644 (file)
@@ -89,6 +89,7 @@ extern void kdb5_list_mkeys (int argc, char **argv);
 extern void kdb5_update_princ_encryption (int argc, char **argv);
 extern krb5_error_code master_key_convert(krb5_context context,
                                          krb5_db_entry *db_entry);
+extern void kdb5_purge_mkeys (int argc, char **argv);
 
 extern void update_ok_file (char *file_name);
 
index c55659d9dcc1cb3d65363df1ef7c910f8d9e8f3c..8db39ac4f2da1254936a12e3cf0926bc41ac2fa5 100644 (file)
@@ -116,6 +116,7 @@ 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;
 
 #if APPLE_PKINIT
     asReqDebug("process_as_req top realm %s name %s\n", 
@@ -431,7 +432,9 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
         /* 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, &master_keylist) == 0) {
+                                    &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";
@@ -479,7 +482,9 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
         /* 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, &master_keylist) == 0) {
+                                    &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";
index 1fb6812a5a9ebaff29422826d4778c423a5608a6..ba8558366183f1dfe3bb26d01132927d5cd356e2 100644 (file)
@@ -576,10 +576,13 @@ tgt_again:
 
         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, &master_keylist) == 0) {
+                                        &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";
index a4025e3f262beffd8c2f418232311f6f020b6e77..7aacca402e0599ebc5a30eddbaae22ef7499c827 100644 (file)
@@ -703,10 +703,13 @@ get_entry_data(krb5_context context,
        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,
-                                        &master_keylist) == 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);
@@ -1374,10 +1377,13 @@ verify_enc_timestamp(krb5_context context, krb5_db_entry *client,
 
     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,
-                                    &master_keylist) == 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;
@@ -2044,10 +2050,13 @@ get_sam_edata(krb5_context context, krb5_kdc_req *request,
        {
           if ((retval = krb5_dbe_find_mkey(context, master_keylist, &assoc,
                                            &mkey_ptr))) {
-               /* try refreshing the mkey list in case it's been updated */
+              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,
-                                          &master_keylist) == 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, &assoc,
                                                    &mkey_ptr))) {
                       return (retval);
@@ -2705,10 +2714,13 @@ static krb5_error_code verify_pkinit_request(
     }
     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,
-                                    &master_keylist) == 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;
index 68d7b869f4bb16789d674f7cb2219c56d5af9a0b..28b4a37ca0e82673d28c9ff8779bd324cdeeda4f 100644 (file)
@@ -449,10 +449,13 @@ kdc_get_server_key(krb5_ticket *ticket, unsigned int flags,
 
     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, &master_keylist) == 0) {
+                                    &master_keyblock, 0, &tmp_mkey_list) == 0) {
+            krb5_dbe_free_key_list(kdc_context, master_keylist);
+            master_keylist = tmp_mkey_list;
             if ((retval = krb5_dbe_find_mkey(kdc_context, master_keylist,
                                              server, &mkey_ptr))) {
                 goto errout;
index f3fd651058593d698f29f876450ad972be72333e..d52a2f6b7de7e42d506294858c306025290dde97 100644 (file)
@@ -2096,11 +2096,14 @@ kadm5_get_principal_keys(void *server_handle /* IN */,
     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,
-                                        &master_keylist) == 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;
@@ -2238,10 +2241,13 @@ kadm5_ret_t kadm5_decrypt_key(void *server_handle,
     dbent.tl_data = entry->tl_data;
     if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist, &dbent,
                                   &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, &master_keylist) == 0) {
+                                    &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,
                                           &dbent, &mkey_ptr))) {
                 return ret;
index 29415308a08c287b1f37281fe72013d07121ccf0..2252c3ad0359d417504522774dcee60d12be035d 100644 (file)
@@ -163,6 +163,16 @@ krb5_dbe_free_mkey_aux_list(krb5_context context, krb5_mkey_aux_node *val)
     }
 }
 
+void
+krb5_dbe_free_tl_data(krb5_context context, krb5_tl_data *tl_data)
+{
+    if (tl_data) {
+        if (tl_data->tl_data_contents)
+            free(tl_data->tl_data_contents);
+        free(tl_data);
+    }
+}
+
 #define kdb_init_lib_lock(a) 0
 #define kdb_destroy_lib_lock(a) (void)0
 #define kdb_lock_lib_lock(a, b) 0
@@ -2404,6 +2414,12 @@ krb5_dbe_update_mkey_aux(krb5_context         context,
     unsigned char *nextloc;
     krb5_mkey_aux_node *aux_data_entry;
 
+    if (!mkey_aux_data_list) {
+        /* delete the KRB5_TL_MKEY_AUX from the entry */
+        krb5_dbe_delete_tl_data(context, entry, KRB5_TL_MKEY_AUX);
+        return (0);
+    }
+
     memset(&tl_data, 0, sizeof(tl_data));
     tl_data.tl_data_type = KRB5_TL_MKEY_AUX;
     /*
@@ -2622,6 +2638,44 @@ krb5_dbe_update_last_pwd_change(context, entry, stamp)
     return (krb5_dbe_update_tl_data(context, entry, &tl_data));
 }
 
+krb5_error_code
+krb5_dbe_delete_tl_data(krb5_context context,
+                        krb5_db_entry *entry,
+                        krb5_int16 tl_data_type) 
+{
+    krb5_tl_data *tl_data, *prev_tl_data, *free_tl_data;
+
+    /*
+     * Find existing entries of the specified type and remove them from the
+     * entry's tl_data list.
+     */
+
+    for (prev_tl_data = tl_data = entry->tl_data; tl_data != NULL;) {
+        if (tl_data->tl_data_type == tl_data_type) {
+            if (tl_data == entry->tl_data) {
+                /* remove from head */
+                entry->tl_data = tl_data->tl_data_next;
+                prev_tl_data = entry->tl_data;
+            } else if (tl_data->tl_data_next == NULL) {
+                /* remove from tail */
+                prev_tl_data->tl_data_next = NULL;
+            } else {
+                /* remove in between */
+                prev_tl_data->tl_data_next = tl_data->tl_data_next;
+            }
+            free_tl_data = tl_data;
+            tl_data = tl_data->tl_data_next;
+            krb5_dbe_free_tl_data(context, free_tl_data);
+            entry->n_tl_data--;
+        } else {
+            tl_data = tl_data->tl_data_next;
+            prev_tl_data = tl_data;
+        }
+    }
+
+    return (0);
+}
+
 krb5_error_code
 krb5_dbe_update_tl_data(context, entry, new_tl_data)
     krb5_context context;
index d0426bd616a291ef510dcaebe635a21dce8aa31f..cd7214d9b65359f40e7bc1b625a36bb4f091ce5e 100644 (file)
@@ -59,6 +59,7 @@ ec KRB5_KDB_CANTREAD_STORED,  "Cannot find/read stored master key"
 ec KRB5_KDB_BADSTORED_MKEY,    "Stored master key is corrupted"
 ec KRB5_KDB_NOACTMASTERKEY,    "Cannot find active master key"
 ec KRB5_KDB_KVNONOMATCH,       "KVNO of new master key does not match expected value"
+ec KRB5_KDB_STORED_MKEY_NOTCURRENT,    "Stored master key is not current"
 
 ec KRB5_KDB_CANTLOCK_DB,       "Insufficient access to lock database"
 
index 34b9bd2b76daf7ba3b8ac5f5f08beb6b4c1daf6d..5c816246814e8382723147020c0d476211d84e24 100644 (file)
@@ -178,15 +178,6 @@ WRAP_VOID (krb5_db2_free_policy,
           ( krb5_context kcontext, osa_policy_ent_t entry ),
           (kcontext, entry));
 
-WRAP (krb5_db2_alloc, void *,
-      ( krb5_context kcontext,  
-       void *ptr, 
-       size_t size ),
-      (kcontext, ptr, size), NULL);
-WRAP_VOID (krb5_db2_free,
-          ( krb5_context kcontext, void *ptr ),
-          (kcontext, ptr));
-
 WRAP_K (krb5_db2_set_master_key_ext,
        ( krb5_context kcontext, char *pwd, krb5_keyblock *key),
        (kcontext, pwd, key));
index f7d19e0ccc58ec63bc51353bc9d4d200824b1044..e52a61897f637d85cf1e60d8af1436f1fcb04027 100644 (file)
@@ -345,7 +345,7 @@ asn1_encode_sequence_of_keys (krb5_key_data *key_data, krb5_int16 n_key_data,
 
 static krb5_error_code
 asn1_decode_sequence_of_keys (krb5_data *in, krb5_key_data **out,
-                             krb5_int16 *n_key_data, int *mkvno)
+                             krb5_int16 *n_key_data, krb5_kvno *mkvno)
 {
     krb5_error_code err;
     ldap_seqof_key_data *p;