#if !defined(lint) && !defined(__CODECENTER__)
static char *rcsid = "$Header$";
#endif
#include <stdio.h>
#include <stdlib.h>
#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_keyblock hist_key;
krb5_db_entry hist_db;
krb5_kvno hist_kvno;
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;
if (from_keyboard)
from_kbd = TRUE;
if (r == NULL) {
if ((ret = krb5_get_default_realm(handle->context, &realm)))
return ret;
} else {
realm = r;
}
if ((ret = krb5_db_setup_mkey_name(handle->context,
handle->params.mkey_name,
realm, NULL, &master_princ)))
goto done;
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,
NULL ,
&master_keyblock);
if (ret)
goto done;
if ((ret = krb5_db_verify_master_key(handle->context, master_princ,
&master_keyblock))) {
krb5_db_fini(handle->context);
return ret;
}
done:
if (r == NULL)
free(realm);
return(ret);
}
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;
memset(&ent, 0, sizeof(ent));
ent.principal = hist_princ;
ent.max_life = KRB5_KDB_DISALLOW_ALL_TIX;
ent.attributes = 0;
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;
hist_princ = NULL;
ret = kadm5_randkey_principal_3(handle, ent.principal, 0, 1, ks,
NULL, NULL);
hist_princ = ent.principal;
if (ret)
goto done;
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, &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;
}
krb5_error_code
kdb_get_entry(kadm5_server_handle_t handle,
krb5_principal principal, krb5_db_entry *kdb,
osa_princ_ent_rec *adb)
{
krb5_error_code ret;
int nprincs;
krb5_boolean more;
krb5_tl_data tl_data;
XDR xdrs;
ret = krb5_db_get_principal(handle->context, principal, kdb, &nprincs,
&more);
if (ret)
return(ret);
if (more) {
krb5_db_free_principal(handle->context, kdb, nprincs);
return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE);
} else if (nprincs != 1) {
krb5_db_free_principal(handle->context, kdb, nprincs);
return(KADM5_UNK_PRINC);
}
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 = hist_kvno;
return(ret);
}
xdrmem_create(&xdrs, 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, 1);
return(KADM5_XDR_FAILURE);
}
xdr_destroy(&xdrs);
}
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, 1);
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_int32 now;
XDR xdrs;
krb5_tl_data tl_data;
int one;
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 = xdralloc_getdata(&xdrs);
ret = krb5_dbe_update_tl_data(handle->context, kdb, &tl_data);
xdr_destroy(&xdrs);
if (ret)
return(ret);
one = 1;
ret = krb5_db_put_principal(handle->context, kdb, &one);
if (ret)
return(ret);
return(0);
}
krb5_error_code
kdb_delete_entry(kadm5_server_handle_t handle, krb5_principal name)
{
int one = 1;
krb5_error_code ret;
ret = krb5_db_delete_principal(handle->context, name, &one);
return 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);
if (ret)
return(ret);
return(0);
}