From: Will Fiveash Date: Tue, 27 Jan 2009 04:16:26 +0000 (+0000) Subject: More review changes: X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c1e6bdf4eba202ad43fb416c884a66a8af24ab5f;p=thirdparty%2Fkrb5.git More review changes: Have both LDAP and DB2 back ends been tried with Will's new code? Looks like some default routines like kdb_def_get_mkey_list won't do anything; is that okay? Done but not tested. "XXX" comments in kdc/extern.h and elsewhere need to be looked into, obviously. Almost done (working on the mkey_convert issue). git-svn-id: svn://anonsvn.mit.edu/krb5/branches/mkey_migrate@21806 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/include/kdb.h b/src/include/kdb.h index ae56568b3e..d60a5c50da 100644 --- a/src/include/kdb.h +++ b/src/include/kdb.h @@ -183,10 +183,10 @@ typedef struct __krb5_key_salt_tuple { #define KRB5_TL_MKEY_AUX 0x000a /* version number for KRB5_TL_ACTKVNO data */ -#define KRB5_TL_ACTKVNO_VER_1 1 +#define KRB5_TL_ACTKVNO_VER 1 /* version number for KRB5_TL_MKEY_AUX data */ -#define KRB5_TL_MKEY_AUX_VER_1 1 +#define KRB5_TL_MKEY_AUX_VER 1 typedef struct _krb5_actkvno_node { struct _krb5_actkvno_node *next; @@ -662,6 +662,15 @@ krb5_db_get_context void krb5_dbe_free_key_data_contents(krb5_context, krb5_key_data *); +void +krb5_dbe_free_key_list(krb5_context, krb5_keylist_node *); + +void +krb5_dbe_free_actkvno_list(krb5_context, krb5_actkvno_node *); + +void +krb5_dbe_free_mkey_aux_list(krb5_context, krb5_mkey_aux_node *); + #define KRB5_KDB_DEF_FLAGS 0 #define KDB_MAX_DB_NAME 128 diff --git a/src/kadmin/dbutil/dump.c b/src/kadmin/dbutil/dump.c index 68a8270a9b..f5b6cd6fee 100644 --- a/src/kadmin/dbutil/dump.c +++ b/src/kadmin/dbutil/dump.c @@ -178,6 +178,7 @@ extern krb5_boolean dbactive; extern int exit_status; extern krb5_context util_context; extern kadm5_config_params global_params; +extern krb5_keylist_node *master_keylist; /* Strings */ @@ -274,48 +275,49 @@ static krb5_error_code master_key_convert(context, db_entry) is_mkey = krb5_principal_compare(context, master_princ, db_entry->princ); - /* XXX WAF: need to fix this! */ - if (is_mkey && db_entry->n_key_data != 1) - fprintf(stderr, - "Master key db entry has %d keys, expecting only 1!\n", - db_entry->n_key_data); - for (i=0; i < db_entry->n_key_data; i++) { - key_data = &db_entry->key_data[i]; - if (key_data->key_data_length == 0) - continue; - retval = krb5_dbekd_decrypt_key_data(context, &master_keyblock, - key_data, &v5plainkey, - &keysalt); - if (retval) - return retval; - - memset(&new_key_data, 0, sizeof(new_key_data)); - - if (is_mkey) { - key_ptr = &new_master_keyblock; - /* override mkey princ's kvno */ - if (global_params.mask & KADM5_CONFIG_KVNO) - kvno = global_params.kvno; - else - kvno = (krb5_kvno) key_data->key_data_kvno; - } else { - key_ptr = &v5plainkey; - kvno = (krb5_kvno) key_data->key_data_kvno; - } - - retval = krb5_dbekd_encrypt_key_data(context, &new_master_keyblock, - key_ptr, &keysalt, - (int) kvno, - &new_key_data); - if (retval) - return retval; - krb5_free_keyblock_contents(context, &v5plainkey); - for (j = 0; j < key_data->key_data_ver; j++) { - if (key_data->key_data_length[j]) { - free(key_data->key_data_contents[j]); - } - } - *key_data = new_key_data; + if (is_mkey) { + retval = add_new_mkey(context, db_entry, &new_master_keyblock); + if (retval) + return retval; + } else { + for (i=0; i < db_entry->n_key_data; i++) { + key_data = &db_entry->key_data[i]; + if (key_data->key_data_length == 0) + continue; + retval = krb5_dbekd_decrypt_key_data(context, &master_keyblock, + key_data, &v5plainkey, + &keysalt); + if (retval) + return retval; + + memset(&new_key_data, 0, sizeof(new_key_data)); + + if (is_mkey) { + key_ptr = &new_master_keyblock; + /* override mkey princ's kvno */ + if (global_params.mask & KADM5_CONFIG_KVNO) + kvno = global_params.kvno; + else + kvno = (krb5_kvno) key_data->key_data_kvno; + } else { + key_ptr = &v5plainkey; + kvno = (krb5_kvno) key_data->key_data_kvno; + } + + retval = krb5_dbekd_encrypt_key_data(context, &new_master_keyblock, + key_ptr, &keysalt, + (int) kvno, + &new_key_data); + if (retval) + return retval; + krb5_free_keyblock_contents(context, &v5plainkey); + for (j = 0; j < key_data->key_data_ver; j++) { + if (key_data->key_data_length[j]) { + free(key_data->key_data_contents[j]); + } + } + *key_data = new_key_data; + } } return 0; } diff --git a/src/kadmin/dbutil/kdb5_mkey.c b/src/kadmin/dbutil/kdb5_mkey.c index 57d469b1dc..d127b41aef 100644 --- a/src/kadmin/dbutil/kdb5_mkey.c +++ b/src/kadmin/dbutil/kdb5_mkey.c @@ -34,6 +34,130 @@ static char *strdate(krb5_timestamp when) return out; } +krb5_error_code +add_new_mkey(krb5_context context, krb5_db_entry *master_entry, krb5_keyblock *new_mkey) +{ + krb5_error_code retval = 0; + int old_key_data_count, i; + krb5_kvno old_kvno, new_mkey_kvno; + krb5_keyblock new_mkeyblock; + krb5_key_data tmp_key_data, *old_key_data; + krb5_enctype new_master_enctype = ENCTYPE_UNKNOWN; + krb5_mkey_aux_node *mkey_aux_data_head = NULL, **mkey_aux_data, + *cur_mkey_aux_data, *next_mkey_aux_data; + krb5_keylist_node *keylist_node; + + /* First save the old keydata */ + old_kvno = krb5_db_get_key_data_kvno(context, master_entry->n_key_data, + master_entry->key_data); + old_key_data_count = master_entry->n_key_data; + old_key_data = master_entry->key_data; + + /* alloc enough space to hold new and existing key_data */ + /* + * The encrypted key is malloc'ed by krb5_dbekd_encrypt_key_data and + * krb5_key_data key_data_contents is a pointer to this key. Using some + * logic from master_key_convert(). + */ + master_entry->key_data = (krb5_key_data *) malloc(sizeof(krb5_key_data) * + (old_key_data_count + 1)); + if (master_entry->key_data == NULL) + return (ENOMEM); + + memset((char *) master_entry->key_data, 0, + sizeof(krb5_key_data) * (old_key_data_count + 1)); + master_entry->n_key_data = old_key_data_count + 1; + + new_mkey_kvno = old_kvno + 1; + /* deal with wrapping? */ + if (new_mkey_kvno == 0) + new_mkey_kvno = 1; /* knvo must not be 0 as this is special value (IGNORE_VNO) */ + + /* Note, mkey does not have salt */ + /* add new mkey encrypted with itself to mkey princ entry */ + if ((retval = krb5_dbekd_encrypt_key_data(context, new_mkey, + new_mkey, NULL, + (int) new_mkey_kvno, + &master_entry->key_data[0]))) { + return (retval); + } + + /* + * Need to decrypt old keys with the current mkey which is in the global + * master_keyblock and encrypt those keys with the latest mkey. And while + * the old keys are being decrypted, use those to create the + * KRB5_TL_MKEY_AUX entries which store the latest mkey encrypted by one of + * the older mkeys. + * + * The new mkey is followed by existing keys. + * + * First, set up for creating a krb5_mkey_aux_node list which will be used + * to update the mkey aux data for the mkey princ entry. + */ + mkey_aux_data_head = (krb5_mkey_aux_node *) malloc(sizeof(krb5_mkey_aux_node)); + if (mkey_aux_data_head == NULL) { + retval = ENOMEM; + goto clean_n_exit; + } + memset(mkey_aux_data_head, 0, sizeof(krb5_mkey_aux_node)); + mkey_aux_data = &mkey_aux_data_head; + + for (keylist_node = master_keylist, i = 1; keylist_node != NULL; + keylist_node = keylist_node->next, i++) { + + /* + * Create a list of krb5_mkey_aux_node nodes. One node contains the new + * mkey encrypted by an old mkey and the old mkey's kvno (one node per + * old mkey). + */ + if (*mkey_aux_data == NULL) { + /* *mkey_aux_data points to next field of previous node */ + *mkey_aux_data = (krb5_mkey_aux_node *) malloc(sizeof(krb5_mkey_aux_node)); + if (*mkey_aux_data == NULL) { + retval = ENOMEM; + goto clean_n_exit; + } + memset(*mkey_aux_data, 0, sizeof(krb5_mkey_aux_node)); + } + + memset(&tmp_key_data, 0, sizeof(tmp_key_data)); + /* encrypt the new mkey with the older mkey */ + retval = krb5_dbekd_encrypt_key_data(context, &keylist_node->keyblock, + new_mkey, + NULL, /* no keysalt */ + (int) new_mkey_kvno, + &tmp_key_data); + if (retval) + goto clean_n_exit; + + (*mkey_aux_data)->latest_mkey = tmp_key_data; + (*mkey_aux_data)->mkey_kvno = keylist_node->kvno; + mkey_aux_data = &((*mkey_aux_data)->next); + + /* + * Store old key in master_entry keydata past the new mkey + */ + retval = krb5_dbekd_encrypt_key_data(context, new_mkey, + &keylist_node->keyblock, + NULL, /* no keysalt */ + (int) keylist_node->kvno, + &master_entry->key_data[i]); + if (retval) + goto clean_n_exit; + } + assert(i == old_key_data_count + 1); + + if ((retval = krb5_dbe_update_mkey_aux(context, master_entry, + mkey_aux_data_head))) { + goto clean_n_exit; + } + +clean_n_exit: + if (mkey_aux_data_head) + krb5_dbe_free_mkey_aux_list(context, mkey_aux_data_head); + return (retval); +} + void kdb5_add_mkey(int argc, char *argv[]) { @@ -47,7 +171,7 @@ kdb5_add_mkey(int argc, char *argv[]) krb5_boolean more = 0; krb5_data pwd; krb5_kvno old_kvno, new_mkey_kvno; - krb5_keyblock new_master_keyblock; + krb5_keyblock new_mkeyblock; krb5_key_data tmp_key_data, *old_key_data; krb5_enctype new_master_enctype = ENCTYPE_UNKNOWN; char *new_mkey_password; @@ -95,8 +219,7 @@ kdb5_add_mkey(int argc, char *argv[]) } retval = krb5_db_get_principal(util_context, master_princ, &master_entry, - &nentries, - &more); + &nentries, &more); if (retval != 0) { com_err(progname, retval, "while setting up master key name"); exit_status++; @@ -137,129 +260,16 @@ kdb5_add_mkey(int argc, char *argv[]) } retval = krb5_c_string_to_key(util_context, new_master_enctype, - &pwd, &master_salt, &new_master_keyblock); + &pwd, &master_salt, &new_mkeyblock); if (retval) { com_err(progname, retval, "while transforming master key from password"); exit_status++; return; } - /* First save the old keydata */ - old_kvno = krb5_db_get_key_data_kvno(util_context, master_entry.n_key_data, - master_entry.key_data); - old_key_data_count = master_entry.n_key_data; - old_key_data = master_entry.key_data; - - /* alloc enough space to hold new and existing key_data */ - /* - * The encrypted key is malloc'ed by krb5_dbekd_encrypt_key_data and - * krb5_key_data key_data_contents is a pointer to this key. Using some - * logic from master_key_convert(). - */ - master_entry.key_data = (krb5_key_data *) malloc(sizeof(krb5_key_data) * - (old_key_data_count + 1)); - if (master_entry.key_data == NULL) { - com_err(progname, ENOMEM, "while adding new master key"); - exit_status++; - return; - } - memset((char *) master_entry.key_data, 0, - sizeof(krb5_key_data) * (old_key_data_count + 1)); - master_entry.n_key_data = old_key_data_count + 1; - - new_mkey_kvno = old_kvno + 1; - /* deal with wrapping? */ - if (new_mkey_kvno == 0) - new_mkey_kvno = 1; /* knvo must not be 0 as this is special value (IGNORE_VNO) */ - - /* Note, mkey does not have salt */ - /* add new mkey encrypted with itself to mkey princ entry */ - if ((retval = krb5_dbekd_encrypt_key_data(util_context, &new_master_keyblock, - &new_master_keyblock, NULL, - (int) new_mkey_kvno, - master_entry.key_data))) { - com_err(progname, retval, "while creating new master key"); - exit_status++; - return; - } - - /* - * Need to decrypt old keys with the current mkey which is in the global - * master_keyblock and encrypt those keys with the latest mkey. And while - * the old keys are being decrypted, use those to create the - * KRB5_TL_MKEY_AUX entries which store the latest mkey encrypted by one of - * the older mkeys. - * - * The new mkey is followed by existing keys. - * - * First, set up for creating a krb5_mkey_aux_node list which will be used - * to update the mkey aux data for the mkey princ entry. - */ - mkey_aux_data_head = (krb5_mkey_aux_node *) malloc(sizeof(krb5_mkey_aux_node)); - if (mkey_aux_data_head == NULL) { - com_err(progname, ENOMEM, "while creating mkey_aux_data"); - exit_status++; - return; - } - memset(mkey_aux_data_head, 0, sizeof(krb5_mkey_aux_node)); - mkey_aux_data = &mkey_aux_data_head; - - for (keylist_node = master_keylist, i = 1; keylist_node != NULL; - keylist_node = keylist_node->next, i++) { - - /* - * Create a list of krb5_mkey_aux_node nodes. One node contains the new - * mkey encrypted by an old mkey and the old mkey's kvno (one node per - * old mkey). - */ - if (*mkey_aux_data == NULL) { - /* *mkey_aux_data points to next field of previous node */ - *mkey_aux_data = (krb5_mkey_aux_node *) malloc(sizeof(krb5_mkey_aux_node)); - if (*mkey_aux_data == NULL) { - com_err(progname, ENOMEM, "while creating mkey_aux_data"); - exit_status++; - return; - } - memset(*mkey_aux_data, 0, sizeof(krb5_mkey_aux_node)); - } - - memset(&tmp_key_data, 0, sizeof(tmp_key_data)); - /* encrypt the new mkey with the older mkey */ - retval = krb5_dbekd_encrypt_key_data(util_context, &keylist_node->keyblock, - &new_master_keyblock, - NULL, /* no keysalt */ - (int) new_mkey_kvno, - &tmp_key_data); - if (retval) { - com_err(progname, retval, "while encrypting master keys"); - exit_status++; - return; - } - - (*mkey_aux_data)->latest_mkey = tmp_key_data; - (*mkey_aux_data)->mkey_kvno = keylist_node->kvno; - mkey_aux_data = &((*mkey_aux_data)->next); - - /* - * Store old key in master_entry keydata past the new mkey - */ - retval = krb5_dbekd_encrypt_key_data(util_context, &new_master_keyblock, - &keylist_node->keyblock, - NULL, /* no keysalt */ - (int) keylist_node->kvno, - &master_entry.key_data[i]); - if (retval) { - com_err(progname, retval, "while encrypting master keys"); - exit_status++; - return; - } - } - - assert(i == old_key_data_count + 1); - - if ((retval = krb5_dbe_update_mkey_aux(util_context, &master_entry, - mkey_aux_data_head))) { - com_err(progname, retval, "while updating mkey aux data"); + retval = add_new_mkey(util_context, &master_entry, &new_mkeyblock); + if (retval) { + com_err(progname, retval, "adding new master key to master principal"); exit_status++; return; } @@ -286,11 +296,11 @@ kdb5_add_mkey(int argc, char *argv[]) if (do_stash) { retval = krb5_db_store_master_key(util_context, - global_params.stash_file, - master_princ, - new_mkey_kvno, - &new_master_keyblock, - mkey_password); + global_params.stash_file, + master_princ, + new_mkey_kvno, + &new_mkeyblock, + mkey_password); if (retval) { com_err(progname, errno, "while storing key"); printf("Warning: couldn't stash master key.\n"); @@ -300,8 +310,8 @@ kdb5_add_mkey(int argc, char *argv[]) (void) krb5_db_fini(util_context); zap((char *)master_keyblock.contents, master_keyblock.length); free(master_keyblock.contents); - zap((char *)new_master_keyblock.contents, new_master_keyblock.length); - free(new_master_keyblock.contents); + zap((char *)new_mkeyblock.contents, new_mkeyblock.length); + free(new_mkeyblock.contents); if (pw_str) { zap(pw_str, pw_size); free(pw_str); @@ -309,12 +319,6 @@ kdb5_add_mkey(int argc, char *argv[]) free(master_salt.data); free(mkey_fullname); - for (cur_mkey_aux_data = mkey_aux_data_head; cur_mkey_aux_data != NULL; - cur_mkey_aux_data = next_mkey_aux_data) { - next_mkey_aux_data = cur_mkey_aux_data->next; - krb5_dbe_free_key_data_contents(util_context, &(cur_mkey_aux_data->latest_mkey)); - free(cur_mkey_aux_data); - } return; } @@ -329,19 +333,33 @@ kdb5_use_mkey(int argc, char *argv[]) *prev_actkvno, *cur_actkvno; krb5_db_entry master_entry; int nentries = 0; - krb5_boolean more = 0; + krb5_boolean more = 0, found; + krb5_keylist_node *keylist_node; if (argc < 2 || argc > 3) { /* usage calls exit */ usage(); } - /* use_kvno = (int) strtol(argv[0], (char **)NULL, 10); */ use_kvno = atoi(argv[1]); if (use_kvno == 0) { com_err(progname, EINVAL, ": 0 is an invalid KVNO value."); exit_status++; return; + } else { + /* verify use_kvno is valid */ + for (keylist_node = master_keylist, found = FALSE; keylist_node != NULL; + keylist_node = keylist_node->next) { + if (use_kvno == keylist_node->kvno) { + found = TRUE; + break; + } + } + if (!found) { + com_err(progname, EINVAL, ": %d is an invalid KVNO value.", use_kvno); + exit_status++; + return; + } } if ((retval = krb5_timeofday(util_context, &now))) { @@ -360,7 +378,6 @@ kdb5_use_mkey(int argc, char *argv[]) * Need to: * * 1. get mkey princ - * 2. verify that mprinc actually has a mkey with the new actkvno * 2. get krb5_actkvno_node list * 3. add use_kvno to actkvno list (sorted in right spot) * 4. update mkey princ's tl data @@ -385,8 +402,6 @@ kdb5_use_mkey(int argc, char *argv[]) return; } - /* XXX WAF: verify that the provided kvno is valid */ - retval = krb5_dbe_lookup_actkvno(util_context, &master_entry, &actkvno_list); if (retval != 0) { com_err(progname, retval, "while setting up master key name"); @@ -478,12 +493,7 @@ kdb5_use_mkey(int argc, char *argv[]) /* clean up */ (void) krb5_db_fini(util_context); free(mkey_fullname); - for (cur_actkvno = actkvno_list; cur_actkvno != NULL;) { - - prev_actkvno = cur_actkvno; - cur_actkvno = cur_actkvno->next; - free(prev_actkvno); - } + krb5_dbe_free_actkvno_list(util_context, actkvno_list); return; } diff --git a/src/kadmin/dbutil/kdb5_util.h b/src/kadmin/dbutil/kdb5_util.h index cc69c90c82..dd74654357 100644 --- a/src/kadmin/dbutil/kdb5_util.h +++ b/src/kadmin/dbutil/kdb5_util.h @@ -88,5 +88,7 @@ extern void update_ok_file (char *file_name); extern int kadm5_create (kadm5_config_params *params); +extern krb5_error_code add_new_mkey(krb5_context, krb5_db_entry *, krb5_keyblock *); + void usage (void); diff --git a/src/kdc/extern.h b/src/kdc/extern.h index d79e1aa179..3b67eb8182 100644 --- a/src/kdc/extern.h +++ b/src/kdc/extern.h @@ -41,7 +41,6 @@ typedef struct __kdc_realm_data { krb5_context realm_context; /* Context to be used for realm */ krb5_keytab realm_keytab; /* keytab to be used for this realm */ char * realm_profile; /* Profile file for this realm */ - krb5_keylist_node * mkey_list; /* list of mkeys in use for this realm */ /* * Database per-realm data. */ @@ -49,13 +48,12 @@ typedef struct __kdc_realm_data { char * realm_stash; /* Stash file name for realm */ char * realm_mpname; /* Master principal name for realm */ krb5_principal realm_mprinc; /* Master principal for realm */ - /* XXX WAF: is realm_mkey the most current key in the keytab (or from - * command line)? Or should this be the active key? I need to make sure - * this is handled properly. what about the kvno of this key? - * or maybe this should go away and be replaced with a function that - * returns the proper mkey given a princ. + /* + * Note realm_mkey is mkey read from stash or keyboard and may not be the + * latest. The mkey_list will have all the mkeys in use. */ krb5_keyblock realm_mkey; /* Master key for this realm */ + krb5_keylist_node * mkey_list; /* list of mkeys in use for this realm */ /* * TGS per-realm data. */ diff --git a/src/kdc/main.c b/src/kdc/main.c index 7a7413905a..4394b6ddc9 100644 --- a/src/kdc/main.c +++ b/src/kdc/main.c @@ -150,9 +150,12 @@ finish_realm(kdc_realm_t *rdp) if (rdp->realm_mprinc) krb5_free_principal(rdp->realm_context, rdp->realm_mprinc); if (rdp->realm_mkey.length && rdp->realm_mkey.contents) { + /* XXX shouldn't memset be zap for safety? */ memset(rdp->realm_mkey.contents, 0, rdp->realm_mkey.length); free(rdp->realm_mkey.contents); } + if (rdp->mkey_list) + krb5_dbe_free_key_list(rdp->realm_context, rdp->mkey_list); krb5_db_fini(rdp->realm_context); if (rdp->realm_tgsprinc) krb5_free_principal(rdp->realm_context, rdp->realm_tgsprinc); diff --git a/src/lib/kadm5/admin.h b/src/lib/kadm5/admin.h index c8617723a4..b2d05ad68a 100644 --- a/src/lib/kadm5/admin.h +++ b/src/lib/kadm5/admin.h @@ -184,7 +184,6 @@ typedef struct _kadm5_principal_ent_t_v2 { krb5_int16 n_tl_data; krb5_tl_data *tl_data; krb5_key_data *key_data; - int foo; /* XXX WAF: just to see if it breaks the build */ } kadm5_principal_ent_rec_v2, *kadm5_principal_ent_t_v2; typedef struct _kadm5_principal_ent_t_v1 { diff --git a/src/lib/kadm5/srv/server_kdb.c b/src/lib/kadm5/srv/server_kdb.c index 31f793ade4..b73444cd60 100644 --- a/src/lib/kadm5/srv/server_kdb.c +++ b/src/lib/kadm5/srv/server_kdb.c @@ -76,8 +76,8 @@ krb5_error_code kdb_init_master(kadm5_server_handle_t handle, #if 0 /************** Begin IFDEF'ed OUT *******************************/ /* - * XXX WAF: since the local mkey may not be latest, hold off on verifying it - * since krb5_db_fetch_mkey_list will do this work. + * krb5_db_fetch_mkey_list will verify mkey so don't call + * krb5_db_verify_master_key() */ if ((ret = krb5_db_verify_master_key(handle->context, master_princ, IGNORE_VNO, &master_keyblock))) { diff --git a/src/lib/kdb/kdb5.c b/src/lib/kdb/kdb5.c index 40de4589ac..d68bf6012f 100644 --- a/src/lib/kdb/kdb5.c +++ b/src/lib/kdb/kdb5.c @@ -111,8 +111,7 @@ kdb_unlock_list() * so there is only a single version. */ void -krb5_dbe_free_key_data_contents(krb5_context context, - krb5_key_data *key) +krb5_dbe_free_key_data_contents(krb5_context context, krb5_key_data *key) { int i, idx; @@ -126,8 +125,21 @@ krb5_dbe_free_key_data_contents(krb5_context context, return; } -static void -krb5_free_actkvno_list(krb5_context context, krb5_actkvno_node *val) +void +krb5_dbe_free_key_list(krb5_context context, krb5_keylist_node *mkey_list) +{ + krb5_keylist_node *cur_node, *next_node; + + for (cur_node = mkey_list; cur_node != NULL; cur_node = next_node) { + next_node = cur_node->next; + krb5_free_keyblock(context, &(cur_node->keyblock)); + krb5_xfree(cur_node); + } + return; +} + +void +krb5_dbe_free_actkvno_list(krb5_context context, krb5_actkvno_node *val) { krb5_actkvno_node *temp, *prev; @@ -138,8 +150,8 @@ krb5_free_actkvno_list(krb5_context context, krb5_actkvno_node *val) } } -static void -krb5_free_mkey_aux_list(krb5_context context, krb5_mkey_aux_node *val) +void +krb5_dbe_free_mkey_aux_list(krb5_context context, krb5_mkey_aux_node *val) { krb5_mkey_aux_node *temp, *prev; @@ -2284,8 +2296,7 @@ krb5_dbe_lookup_mkey_aux(krb5_context context, } else { /* get version to determine how to parse the data */ krb5_kdb_decode_int16(tl_data.tl_data_contents, version); - if (version == KRB5_TL_MKEY_AUX_VER_1) { - + if (version == 1) { /* variable size, must be at least 10 bytes */ if (tl_data.tl_data_length < 10) return (KRB5_KDB_TRUNCATED_RECORD); @@ -2297,7 +2308,7 @@ krb5_dbe_lookup_mkey_aux(krb5_context context, new_data = (krb5_mkey_aux_node *) malloc(sizeof(krb5_mkey_aux_node)); if (new_data == NULL) { - krb5_free_mkey_aux_list(context, head_data); + krb5_dbe_free_mkey_aux_list(context, head_data); return (ENOMEM); } memset(new_data, 0, sizeof(krb5_mkey_aux_node)); @@ -2315,7 +2326,7 @@ krb5_dbe_lookup_mkey_aux(krb5_context context, malloc(new_data->latest_mkey.key_data_length[0]); if (new_data->latest_mkey.key_data_contents[0] == NULL) { - krb5_free_mkey_aux_list(context, head_data); + krb5_dbe_free_mkey_aux_list(context, head_data); return (ENOMEM); } memcpy(new_data->latest_mkey.key_data_contents[0], curloc, @@ -2343,6 +2354,7 @@ krb5_dbe_lookup_mkey_aux(krb5_context context, return (0); } +#if KRB5_TL_MKEY_AUX_VER == 1 krb5_error_code krb5_dbe_update_mkey_aux(krb5_context context, krb5_db_entry * entry, @@ -2377,7 +2389,7 @@ krb5_dbe_update_mkey_aux(krb5_context context, } nextloc = tl_data.tl_data_contents; - version = KRB5_TL_MKEY_AUX_VER_1; + version = KRB5_TL_MKEY_AUX_VER; krb5_kdb_encode_int16(version, nextloc); nextloc += sizeof(krb5_ui_2); @@ -2409,15 +2421,17 @@ krb5_dbe_update_mkey_aux(krb5_context context, return (krb5_dbe_update_tl_data(context, entry, &tl_data)); } +#endif /* KRB5_TL_MKEY_AUX_VER == 1 */ -/* XXX WAF: should probably #ifdef this to be defined if version 1 is in use */ +#if KRB5_TL_ACTKVNO_VER == 1 /* - * If version of the KRB5_TL_ACTKVNO data is KRB5_TL_ACTKVNO_VER_1 then size of + * If version of the KRB5_TL_ACTKVNO data is KRB5_TL_ACTKVNO_VER == 1 then size of * a actkvno tuple {act_kvno, act_time} entry is: */ #define ACTKVNO_TUPLE_SIZE (sizeof(krb5_int16) + sizeof(krb5_int32)) #define act_kvno(cp) (cp) /* return pointer to start of act_kvno data */ #define act_time(cp) ((cp) + sizeof(krb5_int16)) /* return pointer to start of act_time data */ +#endif krb5_error_code krb5_dbe_lookup_actkvno(krb5_context context, @@ -2443,7 +2457,7 @@ krb5_dbe_lookup_actkvno(krb5_context context, } else { /* get version to determine how to parse the data */ krb5_kdb_decode_int16(tl_data.tl_data_contents, version); - if (version == KRB5_TL_ACTKVNO_VER_1) { + if (version == 1) { /* variable size, must be at least 8 bytes */ if (tl_data.tl_data_length < 8) @@ -2461,7 +2475,7 @@ krb5_dbe_lookup_actkvno(krb5_context context, for (i = 0; i < num_actkvno; i++) { new_data = (krb5_actkvno_node *) malloc(sizeof(krb5_actkvno_node)); if (new_data == NULL) { - krb5_free_actkvno_list(context, head_data); + krb5_dbe_free_actkvno_list(context, head_data); return (ENOMEM); } memset(new_data, 0, sizeof(krb5_actkvno_node)); @@ -2492,6 +2506,7 @@ krb5_dbe_lookup_actkvno(krb5_context context, /* * Add KRB5_TL_ACTKVNO TL data entries to krb5_db_entry *entry */ +#if KRB5_TL_ACTKVNO_VER == 1 krb5_error_code krb5_dbe_update_actkvno(krb5_context context, krb5_db_entry *entry, @@ -2516,7 +2531,7 @@ krb5_dbe_update_actkvno(krb5_context context, return (ENOMEM); /* add the current version # for the data format used for KRB5_TL_ACTKVNO */ - version = KRB5_TL_ACTKVNO_VER_1; + version = KRB5_TL_ACTKVNO_VER; krb5_kdb_encode_int16(version, (unsigned char *) new_tl_data.tl_data_contents); for (cur_actkvno = actkvno_list; cur_actkvno != NULL; @@ -2549,6 +2564,7 @@ krb5_dbe_update_actkvno(krb5_context context, return (retval); } +#endif /* KRB5_TL_ACTKVNO_VER == 1 */ krb5_error_code krb5_dbe_update_last_pwd_change(context, entry, stamp) diff --git a/src/lib/kdb/kdb_default.c b/src/lib/kdb/kdb_default.c index c29065537e..82b2ced08c 100644 --- a/src/lib/kdb/kdb_default.c +++ b/src/lib/kdb/kdb_default.c @@ -288,7 +288,7 @@ krb5_db_def_fetch_mkey_stash(krb5_context context, if (fread((krb5_pointer) key->contents, sizeof(key->contents[0]), key->length, kf) != key->length) { retval = KRB5_KDB_CANTREAD_STORED; - memset(key->contents, 0, key->length); + zap(key->contents, key->length); free(key->contents); key->contents = 0; } else @@ -471,7 +471,7 @@ krb5_def_verify_master_key(krb5_context context, kvno, master_entry.key_data->key_data_kvno); } - memset((char *)tempkey.contents, 0, tempkey.length); + zap((char *)tempkey.contents, tempkey.length); krb5_xfree(tempkey.contents); krb5_db_free_principal(context, &master_entry, nprinc); @@ -489,8 +489,7 @@ krb5_def_fetch_mkey_list(krb5_context context, krb5_db_entry master_entry; int nprinc; krb5_boolean more, found_key = FALSE; - krb5_keyblock tmp_clearkey; - const krb5_keyblock *current_mkey; + krb5_keyblock cur_mkey; krb5_keylist_node *mkey_list_head = NULL, **mkey_list_node; krb5_key_data *key_data; krb5_mkey_aux_node *mkey_aux_data_list, *aux_data_entry; @@ -499,7 +498,7 @@ krb5_def_fetch_mkey_list(krb5_context context, if (mkeys_list == NULL) return (EINVAL); - memset(&tmp_clearkey, 0, sizeof(tmp_clearkey)); + memset(&cur_mkey, 0, sizeof(cur_mkey)); nprinc = 1; if ((retval = krb5_db_get_principal(context, mprinc, @@ -523,8 +522,7 @@ krb5_def_fetch_mkey_list(krb5_context context, if (mkey->enctype == master_entry.key_data[0].key_data_type[0]) { if (krb5_dbekd_decrypt_key_data(context, mkey, &master_entry.key_data[0], - &tmp_clearkey, NULL) == 0) { - current_mkey = mkey; + &cur_mkey, NULL) == 0) { found_key = TRUE; } } @@ -545,7 +543,7 @@ krb5_def_fetch_mkey_list(krb5_context context, if (aux_data_entry->mkey_kvno == mkvno) { if (krb5_dbekd_decrypt_key_data(context, mkey, &aux_data_entry->latest_mkey, - &tmp_clearkey, NULL) == 0) { + &cur_mkey, NULL) == 0) { found_key = TRUE; break; } @@ -559,9 +557,8 @@ krb5_def_fetch_mkey_list(krb5_context context, if (mkey->enctype == aux_data_entry->latest_mkey.key_data_type[0] && (krb5_dbekd_decrypt_key_data(context, mkey, &aux_data_entry->latest_mkey, - &tmp_clearkey, NULL) == 0)) { + &cur_mkey, NULL) == 0)) { found_key = TRUE; - /* XXX WAF: should I issue warning about kvno not matching? */ break; } } @@ -572,7 +569,6 @@ krb5_def_fetch_mkey_list(krb5_context context, goto clean_n_exit; } } - current_mkey = &tmp_clearkey; } /* @@ -587,12 +583,16 @@ krb5_def_fetch_mkey_list(krb5_context context, } memset(mkey_list_head, 0, sizeof(krb5_keylist_node)); - mkey_list_node = &mkey_list_head; - /* XXX WAF: optimize by setting the first mkey_list_node to current mkey and - * if there are any others then do for loop below. */ + /* Set mkey_list_head to the current mkey as an optimization. */ + /* mkvno may not be latest so ... */ + mkey_list_head->kvno = master_entry.key_data[0].key_data_kvno; + /* this is the latest clear mkey (avoids a redundant decrypt) */ + mkey_list_head->keyblock = cur_mkey; - for (i = 0; i < master_entry.n_key_data; i++) { + /* loop through any other master keys creating a list of krb5_keylist_nodes */ + mkey_list_node = &mkey_list_head->next; + for (i = 1; i < master_entry.n_key_data; i++) { if (*mkey_list_node == NULL) { /* *mkey_list_node points to next field of previous node */ *mkey_list_node = (krb5_keylist_node *) malloc(sizeof(krb5_keylist_node)); @@ -603,7 +603,7 @@ krb5_def_fetch_mkey_list(krb5_context context, memset(*mkey_list_node, 0, sizeof(krb5_keylist_node)); } key_data = &master_entry.key_data[i]; - retval = krb5_dbekd_decrypt_key_data(context, current_mkey, + retval = krb5_dbekd_decrypt_key_data(context, &cur_mkey, key_data, &((*mkey_list_node)->keyblock), NULL); @@ -618,21 +618,10 @@ krb5_def_fetch_mkey_list(krb5_context context, clean_n_exit: - if (tmp_clearkey.contents) { - memset(tmp_clearkey.contents, 0, tmp_clearkey.length); - krb5_db_free(context, tmp_clearkey.contents); - } - krb5_db_free_principal(context, &master_entry, nprinc); - if (retval != 0) { - krb5_keylist_node *cur_node, *next_node; - for (cur_node = mkey_list_head; cur_node != NULL; cur_node = next_node) { - next_node = cur_node->next; - krb5_free_keyblock(context, &(cur_node->keyblock)); - krb5_xfree(cur_node); - } - } + if (retval != 0) + krb5_dbe_free_key_list(context, mkey_list_head); return retval; } diff --git a/src/lib/kdb/libkdb5.exports b/src/lib/kdb/libkdb5.exports index c202f988f1..3cc0816d3b 100644 --- a/src/lib/kdb/libkdb5.exports +++ b/src/lib/kdb/libkdb5.exports @@ -37,7 +37,10 @@ krb5_dbe_find_act_mkey krb5_dbe_fetch_act_key_list krb5_dbe_find_enctype krb5_dbe_find_mkey +krb5_dbe_free_actkvno_list krb5_dbe_free_key_data_contents +krb5_dbe_free_mkey_aux_list +krb5_dbe_free_key_list krb5_dbe_lookup_last_pwd_change krb5_dbe_lookup_actkvno krb5_dbe_lookup_mkvno diff --git a/src/plugins/kdb/ldap/ldap_exp.c b/src/plugins/kdb/ldap/ldap_exp.c index 2b3da3005b..2292f55cca 100644 --- a/src/plugins/kdb/ldap/ldap_exp.c +++ b/src/plugins/kdb/ldap/ldap_exp.c @@ -78,8 +78,8 @@ kdb_vftabl kdb_function_table = { /* optional functions */ /* set_master_key */ krb5_ldap_set_mkey, /* get_master_key */ krb5_ldap_get_mkey, - /* set_master_key_list */ NULL, - /* get_master_key_list */ NULL, + /* set_master_key_list */ krb5_ldap_set_mkey_list, + /* get_master_key_list */ krb5_ldap_get_mkey_list, /* setup_master_key_name */ NULL, /* store_master_key */ NULL, /* fetch_master_key */ NULL /* krb5_ldap_fetch_mkey */, diff --git a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_realm.c b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_realm.c index c13d967108..60d9e25f72 100644 --- a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_realm.c +++ b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_realm.c @@ -2379,6 +2379,8 @@ kdb_ldap_create_principal (context, princ, op, pblock) krb5_ldap_context *ldap_context=NULL; struct iterate_args iargs; krb5_data *pdata; + krb5_timestamp now; + krb5_actkvno_node actkvno; if ((pblock == NULL) || (context == NULL)) { retval = EINVAL; @@ -2425,14 +2427,12 @@ kdb_ldap_create_principal (context, princ, op, pblock) entry.tl_data = tl_data; entry.n_tl_data += 1; /* Set the creator's name */ - { - krb5_timestamp now; - if ((retval = krb5_timeofday(context, &now))) - goto cleanup; - if ((retval = krb5_dbe_update_mod_princ_data_new(context, &entry, - now, &db_create_princ))) - goto cleanup; - } + if ((retval = krb5_timeofday(context, &now))) + goto cleanup; + if ((retval = krb5_dbe_update_mod_princ_data_new(context, &entry, + now, &db_create_princ))) + goto cleanup; + entry.attributes = pblock->flags; entry.max_life = pblock->max_life; entry.max_renewable_life = pblock->max_rlife; @@ -2507,6 +2507,17 @@ kdb_ldap_create_principal (context, princ, op, pblock) if (retval) { goto cleanup; } + /* + * There should always be at least one "active" mkey so creating the + * KRB5_TL_ACTKVNO entry now so the initial mkey is active. + */ + actkvno.next = NULL; + actkvno.act_kvno = kvno; + actkvno.act_time = now; + retval = krb5_dbe_update_actkvno(context, &entry, &actkvno); + if (retval) + goto cleanup; + break; case NULL_KEY: diff --git a/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h index 74bf4b17e9..802ab0fc36 100644 --- a/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h +++ b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h @@ -266,6 +266,12 @@ krb5_ldap_get_mkey(krb5_context, krb5_keyblock **); krb5_error_code krb5_ldap_set_mkey(krb5_context, char *, krb5_keyblock *); +krb5_error_code +krb5_ldap_get_mkey_list (krb5_context context, krb5_keylist_node **key_list); + +krb5_error_code +krb5_ldap_set_mkey_list(krb5_context, krb5_keylist_node *); + krb5_error_code krb5_ldap_create(krb5_context , char *, char **); diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_fetch_mkey.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_fetch_mkey.c index 9a364192ad..6da0806641 100644 --- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_fetch_mkey.c +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_fetch_mkey.c @@ -98,3 +98,45 @@ krb5_ldap_set_mkey (context, pwd, key) memcpy(r_params->mkey.contents, key->contents, key->length); return 0; } + +krb5_error_code +krb5_ldap_get_mkey_list (krb5_context context, krb5_keylist_node **key_list) + +{ + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + + /* Clear the global error string */ + krb5_clear_error_message(context); + + dal_handle = context->dal_handle; + ldap_context = (krb5_ldap_context *) dal_handle->db_context; + + if (ldap_context == NULL || ldap_context->lrparams == NULL) + return KRB5_KDB_DBNOTINITED; + + *key_list = ldap_context->lrparams->mkey_list; + return 0; +} + +krb5_error_code +krb5_ldap_set_mkey_list(krb5_context context, krb5_keylist_node *key_list) +{ + kdb5_dal_handle *dal_handle=NULL; + krb5_ldap_context *ldap_context=NULL; + krb5_ldap_realm_params *r_params = NULL; + + /* Clear the global error string */ + krb5_clear_error_message(context); + + dal_handle = context->dal_handle; + ldap_context = (krb5_ldap_context *) dal_handle->db_context; + + if (ldap_context == NULL || ldap_context->lrparams == NULL) + return KRB5_KDB_DBNOTINITED; + + r_params = ldap_context->lrparams; + r_params->mkey_list = key_list; + return 0; +} + diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.h b/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.h index ffe6c36658..db17509aeb 100644 --- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.h +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.h @@ -68,6 +68,7 @@ typedef struct _krb5_ldap_realm_params { char **passwdservers; krb5_tl_data *tl_data; krb5_keyblock mkey; + krb5_keylist_node *mkey_list; /* all master keys in use for the realm */ long mask; } krb5_ldap_realm_params;