From: Will Fiveash Date: Fri, 30 Jan 2009 20:07:37 +0000 (+0000) Subject: Implemented kdb5_util purge_meys X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b460e5c50063b1a69109bdafb4f833cb95fb107c;p=thirdparty%2Fkrb5.git Implemented kdb5_util purge_meys 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 --- diff --git a/src/include/kdb.h b/src/include/kdb.h index bcf0bee570..240ac0fd52 100644 --- a/src/include/kdb.h +++ b/src/include/kdb.h @@ -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 diff --git a/src/kadmin/dbutil/kdb5_create.c b/src/kadmin/dbutil/kdb5_create.c index ebf07b490a..6a638a3512 100644 --- a/src/kadmin/dbutil/kdb5_create.c +++ b/src/kadmin/dbutil/kdb5_create.c @@ -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; diff --git a/src/kadmin/dbutil/kdb5_mkey.c b/src/kadmin/dbutil/kdb5_mkey.c index 1be680005b..53c0102f43 100644 --- a/src/kadmin/dbutil/kdb5_mkey.c +++ b/src/kadmin/dbutil/kdb5_mkey.c @@ -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; +} diff --git a/src/kadmin/dbutil/kdb5_util.c b/src/kadmin/dbutil/kdb5_util.c index 460160a048..6cb70c1cdf 100644 --- a/src/kadmin/dbutil/kdb5_util.c +++ b/src/kadmin/dbutil/kdb5_util.c @@ -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++; diff --git a/src/kadmin/dbutil/kdb5_util.h b/src/kadmin/dbutil/kdb5_util.h index 09290d76d5..6e99ac3783 100644 --- a/src/kadmin/dbutil/kdb5_util.h +++ b/src/kadmin/dbutil/kdb5_util.h @@ -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); diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c index c55659d9dc..8db39ac4f2 100644 --- a/src/kdc/do_as_req.c +++ b/src/kdc/do_as_req.c @@ -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"; diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c index 1fb6812a5a..ba85583661 100644 --- a/src/kdc/do_tgs_req.c +++ b/src/kdc/do_tgs_req.c @@ -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"; diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c index a4025e3f26..7aacca402e 100644 --- a/src/kdc/kdc_preauth.c +++ b/src/kdc/kdc_preauth.c @@ -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; diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c index 68d7b869f4..28b4a37ca0 100644 --- a/src/kdc/kdc_util.c +++ b/src/kdc/kdc_util.c @@ -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; diff --git a/src/lib/kadm5/srv/svr_principal.c b/src/lib/kadm5/srv/svr_principal.c index f3fd651058..d52a2f6b7d 100644 --- a/src/lib/kadm5/srv/svr_principal.c +++ b/src/lib/kadm5/srv/svr_principal.c @@ -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; diff --git a/src/lib/kdb/kdb5.c b/src/lib/kdb/kdb5.c index 29415308a0..2252c3ad03 100644 --- a/src/lib/kdb/kdb5.c +++ b/src/lib/kdb/kdb5.c @@ -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; diff --git a/src/lib/krb5/error_tables/kdb5_err.et b/src/lib/krb5/error_tables/kdb5_err.et index d0426bd616..cd7214d9b6 100644 --- a/src/lib/krb5/error_tables/kdb5_err.et +++ b/src/lib/krb5/error_tables/kdb5_err.et @@ -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" diff --git a/src/plugins/kdb/db2/db2_exp.c b/src/plugins/kdb/db2/db2_exp.c index 34b9bd2b76..5c81624681 100644 --- a/src/plugins/kdb/db2/db2_exp.c +++ b/src/plugins/kdb/db2/db2_exp.c @@ -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)); diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c index f7d19e0ccc..e52a61897f 100644 --- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c @@ -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;