/* * Fetch the current history key(s), creating the history principal if * necessary. Database created since krb5 1.3 will have only one key, but * databases created before that may have multiple keys (of the same kvno) * and we need to try them all. History keys will be returned in a list * terminated by an entry with enctype 0. */ krb5_error_code kdb_get_hist_key(kadm5_server_handle_t handle, krb5_keyblock **keyblocks_out, krb5_kvno *kvno_out) { krb5_error_code ret; krb5_db_entry *kdb; krb5_keyblock *mkey, *kblist = NULL; krb5_int16 i; /* Fetch the history principal, creating it if necessary. */ ret = kdb_get_entry(handle, hist_princ, &kdb, NULL); if (ret == KADM5_UNK_PRINC) { ret = create_hist(handle); if (ret) return ret; ret = kdb_get_entry(handle, hist_princ, &kdb, NULL); } if (ret) return ret; if (kdb->n_key_data <= 0) { ret = KRB5_KDB_NO_MATCHING_KEY; k5_setmsg(handle->context, ret, _("History entry contains no key data")); goto done; } ret = krb5_dbe_find_mkey(handle->context, kdb, &mkey); if (ret) goto done; kblist = k5calloc(kdb->n_key_data + 1, sizeof(*kblist), &ret); if (kblist == NULL) goto done; for (i = 0; i < kdb->n_key_data; i++) { ret = krb5_dbe_decrypt_key_data(handle->context, mkey, &kdb->key_data[i], &kblist[i], NULL); if (ret) goto done; } *keyblocks_out = kblist; kblist = NULL; *kvno_out = kdb->key_data[0].key_data_kvno; done: kdb_free_entry(handle, kdb, NULL); kdb_free_keyblocks(handle, kblist); return ret; }
/* * Function: kdb_init_hist * * Purpose: Initializes the global history variables. * * Arguments: * * handle (r) kadm5 api server handle * r (r) realm of history principal to use, or NULL * * Effects: This function sets the value of the following global * variables: * * hist_princ krb5_principal holding the history principal * hist_db krb5_db_entry of the history principal * hist_key krb5_keyblock holding the history principal's key * hist_encblock krb5_encrypt_block holding the procssed hist_key * hist_kvno the version number of the history key * * If the history principal does not already exist, this function * attempts to create it with kadm5_create_principal. WARNING! * If the history principal is deleted and this function is executed * (by kadmind, or kadmin.local, or anything else with permission), * the principal will be assigned a new random key and all existing * password history information will become useless. */ krb5_error_code kdb_init_hist(kadm5_server_handle_t handle, char *r) { int ret = 0; char *realm, *hist_name; krb5_key_data *key_data; krb5_key_salt_tuple ks[1]; if (r == NULL) { if ((ret = krb5_get_default_realm(handle->context, &realm))) return ret; } else { realm = r; } if ((hist_name = (char *) malloc(strlen(KADM5_HIST_PRINCIPAL) + strlen(realm) + 2)) == NULL) goto done; (void) sprintf(hist_name, "%s@%s", KADM5_HIST_PRINCIPAL, realm); if ((ret = krb5_parse_name(handle->context, hist_name, &hist_princ))) goto done; if ((ret = kdb_get_entry(handle, hist_princ, &hist_db, NULL))) { kadm5_principal_ent_rec ent; if (ret != KADM5_UNK_PRINC) goto done; /* try to create the principal */ memset(&ent, 0, sizeof(ent)); ent.principal = hist_princ; ent.max_life = KRB5_KDB_DISALLOW_ALL_TIX; ent.attributes = 0; /* this uses hist_kvno. So we set it to 2, which will be the correct value once the principal is created and randomized. Of course, it doesn't make sense to keep a history for the history principal, anyway. */ hist_kvno = 2; ks[0].ks_enctype = handle->params.enctype; ks[0].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; ret = kadm5_create_principal_3(handle, &ent, (KADM5_PRINCIPAL | KADM5_MAX_LIFE | KADM5_ATTRIBUTES), 1, ks, "to-be-random"); if (ret) goto done; /* this won't let us randomize the hist_princ. So we cheat. */ hist_princ = NULL; ret = kadm5_randkey_principal_3(handle, ent.principal, 0, 1, ks, NULL, NULL); hist_princ = ent.principal; if (ret) goto done; /* now read the newly-created kdb record out of the database. */ if ((ret = kdb_get_entry(handle, hist_princ, &hist_db, NULL))) goto done; } ret = krb5_dbe_find_enctype(handle->context, &hist_db, handle->params.enctype, -1, -1, &key_data); if (ret) goto done; ret = krb5_dbekd_decrypt_key_data(handle->context, &handle->master_keyblock, key_data, &hist_key, NULL); if (ret) goto done; hist_kvno = key_data->key_data_kvno; done: free(hist_name); if (r == NULL) free(realm); return ret; }