#include "k5-int.h"
#include <kadm5/admin.h>
#include "server_internal.h"
krb5_principal master_princ;
krb5_keyblock master_keyblock;
krb5_db_entry master_db;
krb5_principal hist_princ;
krb5_error_code kdb_init_master(kadm5_server_handle_t handle,
char *r, int from_keyboard)
{
int ret = 0;
char *realm;
krb5_boolean from_kbd = FALSE;
krb5_kvno mkvno = IGNORE_VNO;
if (from_keyboard)
from_kbd = TRUE;
if (r == NULL) {
if ((ret = krb5_get_default_realm(handle->context, &realm)))
return ret;
} else {
realm = r;
}
krb5_free_principal(handle->context, master_princ);
master_princ = NULL;
if ((ret = krb5_db_setup_mkey_name(handle->context,
handle->params.mkey_name,
realm, NULL, &master_princ)))
goto done;
krb5_free_keyblock_contents(handle->context, &master_keyblock);
master_keyblock.enctype = handle->params.enctype;
ret = krb5_db_fetch_mkey(handle->context, master_princ,
master_keyblock.enctype, from_kbd,
FALSE ,
handle->params.stash_file,
&mkvno ,
NULL
,
&master_keyblock);
if (ret)
goto done;
ret = krb5_db_fetch_mkey_list(handle->context, master_princ,
&master_keyblock);
if (ret)
krb5_db_fini(handle->context);
done:
if (r == NULL)
free(realm);
return(ret);
}
krb5_error_code
kdb_get_active_mkey(kadm5_server_handle_t handle, krb5_kvno *act_kvno_out,
krb5_keyblock **act_mkey_out)
{
krb5_error_code ret;
krb5_actkvno_node *active_mkey_list;
ret = krb5_dbe_fetch_act_key_list(handle->context, master_princ,
&active_mkey_list);
if (ret)
return ret;
ret = krb5_dbe_find_act_mkey(handle->context, active_mkey_list,
act_kvno_out, act_mkey_out);
krb5_dbe_free_actkvno_list(handle->context, active_mkey_list);
return ret;
}
krb5_error_code kdb_init_hist(kadm5_server_handle_t handle, char *r)
{
int ret = 0;
char *realm, *hist_name;
if (r == NULL) {
if ((ret = krb5_get_default_realm(handle->context, &realm)))
return ret;
} else {
realm = r;
}
if (asprintf(&hist_name, "%s@%s", KADM5_HIST_PRINCIPAL, realm) < 0) {
hist_name = NULL;
goto done;
}
krb5_free_principal(handle->context, hist_princ);
hist_princ = NULL;
if ((ret = krb5_parse_name(handle->context, hist_name, &hist_princ)))
goto done;
done:
free(hist_name);
if (r == NULL)
free(realm);
return ret;
}
static krb5_error_code
create_hist(kadm5_server_handle_t handle)
{
kadm5_ret_t ret;
krb5_key_salt_tuple ks[1];
kadm5_principal_ent_rec ent;
long mask = KADM5_PRINCIPAL | KADM5_MAX_LIFE | KADM5_ATTRIBUTES;
memset(&ent, 0, sizeof(ent));
ent.principal = hist_princ;
ent.max_life = KRB5_KDB_DISALLOW_ALL_TIX;
ent.attributes = 0;
ks[0].ks_enctype = handle->params.enctype;
ks[0].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL;
ret = kadm5_create_principal_3(handle, &ent, mask, 1, ks, NULL);
if (ret)
return ret;
return kadm5_randkey_principal_3(handle, ent.principal, 0, 1, ks,
NULL, NULL);
}
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;
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;
}
void
kdb_free_keyblocks(kadm5_server_handle_t handle, krb5_keyblock *keyblocks)
{
krb5_keyblock *kb;
if (keyblocks == NULL)
return;
for (kb = keyblocks; kb->enctype != 0; kb++)
krb5_free_keyblock_contents(handle->context, kb);
free(keyblocks);
}
krb5_error_code
kdb_get_entry(kadm5_server_handle_t handle,
krb5_principal principal, krb5_db_entry **kdb_ptr,
osa_princ_ent_rec *adb)
{
krb5_error_code ret;
krb5_tl_data tl_data;
XDR xdrs;
krb5_db_entry *kdb;
*kdb_ptr = NULL;
ret = krb5_db_get_principal(handle->context, principal, 0, &kdb);
if (ret == KRB5_KDB_NOENTRY)
return(KADM5_UNK_PRINC);
if (ret)
return(ret);
if (adb) {
memset(adb, 0, sizeof(*adb));
tl_data.tl_data_type = KRB5_TL_KADM_DATA;
if ((ret = krb5_dbe_lookup_tl_data(handle->context, kdb, &tl_data))
|| (tl_data.tl_data_length == 0)) {
adb->admin_history_kvno = INITIAL_HIST_KVNO;
*kdb_ptr = kdb;
return(ret);
}
xdrmem_create(&xdrs, (caddr_t)tl_data.tl_data_contents,
tl_data.tl_data_length, XDR_DECODE);
if (! xdr_osa_princ_ent_rec(&xdrs, adb)) {
xdr_destroy(&xdrs);
krb5_db_free_principal(handle->context, kdb);
return(KADM5_XDR_FAILURE);
}
xdr_destroy(&xdrs);
}
*kdb_ptr = kdb;
return(0);
}
krb5_error_code
kdb_free_entry(kadm5_server_handle_t handle,
krb5_db_entry *kdb, osa_princ_ent_rec *adb)
{
XDR xdrs;
if (kdb)
krb5_db_free_principal(handle->context, kdb);
if (adb) {
xdrmem_create(&xdrs, NULL, 0, XDR_FREE);
xdr_osa_princ_ent_rec(&xdrs, adb);
xdr_destroy(&xdrs);
}
return(0);
}
krb5_error_code
kdb_put_entry(kadm5_server_handle_t handle,
krb5_db_entry *kdb, osa_princ_ent_rec *adb)
{
krb5_error_code ret;
krb5_timestamp now;
XDR xdrs;
krb5_tl_data tl_data;
ret = krb5_timeofday(handle->context, &now);
if (ret)
return(ret);
ret = krb5_dbe_update_mod_princ_data(handle->context, kdb, now,
handle->current_caller);
if (ret)
return(ret);
xdralloc_create(&xdrs, XDR_ENCODE);
if(! xdr_osa_princ_ent_rec(&xdrs, adb)) {
xdr_destroy(&xdrs);
return(KADM5_XDR_FAILURE);
}
tl_data.tl_data_type = KRB5_TL_KADM_DATA;
tl_data.tl_data_length = xdr_getpos(&xdrs);
tl_data.tl_data_contents = (krb5_octet *)xdralloc_getdata(&xdrs);
ret = krb5_dbe_update_tl_data(handle->context, kdb, &tl_data);
xdr_destroy(&xdrs);
if (ret)
return(ret);
kdb->mask |= KADM5_TL_DATA;
ret = krb5_db_put_principal(handle->context, kdb);
if (ret)
return(ret);
return(0);
}
krb5_error_code
kdb_delete_entry(kadm5_server_handle_t handle, krb5_principal name)
{
krb5_error_code ret;
ret = krb5_db_delete_principal(handle->context, name);
return (ret == KRB5_KDB_NOENTRY) ? KADM5_UNK_PRINC : ret;
}
typedef struct _iter_data {
void (*func)(void *, krb5_principal);
void *data;
} iter_data;
static krb5_error_code
kdb_iter_func(krb5_pointer data, krb5_db_entry *kdb)
{
iter_data *id = (iter_data *) data;
(*(id->func))(id->data, kdb->princ);
return(0);
}
krb5_error_code
kdb_iter_entry(kadm5_server_handle_t handle, char *match_entry,
void (*iter_fct)(void *, krb5_principal), void *data)
{
iter_data id;
krb5_error_code ret;
id.func = iter_fct;
id.data = data;
ret = krb5_db_iterate(handle->context, match_entry, kdb_iter_func, &id, 0);
if (ret)
return(ret);
return(0);
}