Merge pull request #12 from nicowilliams/krb5_admin_patches_2nd
Krb5 admin patches 2nd This has all the patches needed for krb5_admind to build and pass most tests, that includes: - more kadm5 API compatibility (including very basic profile functionality) - multi-kvno support (useful for key rollovers) (a test for this is included in tests/db/check-kdc) Unfinished: - password history (currently uses key history, needs to be separated and use digests) - policies (only default policy allowed) - mit kdb changes not tested yet Signed-off-by: Love Hörnquist Åstrand <lha@h5l.org>
This commit is contained in:
@@ -44,6 +44,7 @@ static struct units acl_units[] = {
|
||||
{ "modify", KADM5_PRIV_MODIFY },
|
||||
{ "add", KADM5_PRIV_ADD },
|
||||
{ "get", KADM5_PRIV_GET },
|
||||
{ "get-keys", KADM5_PRIV_GET_KEYS },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
@@ -177,6 +178,8 @@ check_flags (unsigned op,
|
||||
|
||||
if(res & KADM5_PRIV_GET)
|
||||
return KADM5_AUTH_GET;
|
||||
if(res & KADM5_PRIV_GET_KEYS)
|
||||
return KADM5_AUTH_GET_KEYS;
|
||||
if(res & KADM5_PRIV_ADD)
|
||||
return KADM5_AUTH_ADD;
|
||||
if(res & KADM5_PRIV_MODIFY)
|
||||
|
@@ -508,6 +508,7 @@ ad_get_cred(kadm5_ad_context *context, const char *password)
|
||||
static kadm5_ret_t
|
||||
kadm5_ad_chpass_principal(void *server_handle,
|
||||
krb5_principal principal,
|
||||
int keepold,
|
||||
const char *password)
|
||||
{
|
||||
kadm5_ad_context *context = server_handle;
|
||||
@@ -515,6 +516,9 @@ kadm5_ad_chpass_principal(void *server_handle,
|
||||
int result_code;
|
||||
kadm5_ret_t ret;
|
||||
|
||||
if (keepold)
|
||||
return KADM5_KEEPOLD_NOSUPP;
|
||||
|
||||
ret = ad_get_cred(context, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1224,14 +1228,21 @@ kadm5_ad_modify_principal(void *server_handle,
|
||||
#endif
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static kadm5_ret_t
|
||||
kadm5_ad_randkey_principal(void *server_handle,
|
||||
krb5_principal principal,
|
||||
krb5_boolean keepold,
|
||||
int n_ks_tuple,
|
||||
krb5_key_salt_tuple *ks_tuple,
|
||||
krb5_keyblock **keys,
|
||||
int *n_keys)
|
||||
{
|
||||
kadm5_ad_context *context = server_handle;
|
||||
|
||||
if (keepold)
|
||||
return KADM5_KEEPOLD_NOSUPP;
|
||||
|
||||
/*
|
||||
* random key
|
||||
*/
|
||||
@@ -1321,6 +1332,7 @@ kadm5_ad_rename_principal(void *server_handle,
|
||||
static kadm5_ret_t
|
||||
kadm5_ad_chpass_principal_with_key(void *server_handle,
|
||||
krb5_principal princ,
|
||||
int keepold,
|
||||
int n_key_data,
|
||||
krb5_key_data *key_data)
|
||||
{
|
||||
@@ -1329,6 +1341,18 @@ kadm5_ad_chpass_principal_with_key(void *server_handle,
|
||||
return KADM5_RPC_ERROR;
|
||||
}
|
||||
|
||||
static kadm5_ret_t
|
||||
kadm5_ad_lock(void *server_handle)
|
||||
{
|
||||
return ENOTSUP;
|
||||
}
|
||||
|
||||
static kadm5_ret_t
|
||||
kadm5_ad_unlock(void *server_handle)
|
||||
{
|
||||
return ENOTSUP;
|
||||
}
|
||||
|
||||
static void
|
||||
set_funcs(kadm5_ad_context *c)
|
||||
{
|
||||
@@ -1345,6 +1369,8 @@ set_funcs(kadm5_ad_context *c)
|
||||
SET(c, modify_principal);
|
||||
SET(c, randkey_principal);
|
||||
SET(c, rename_principal);
|
||||
SET(c, lock);
|
||||
SET(c, unlock);
|
||||
}
|
||||
|
||||
kadm5_ret_t
|
||||
|
@@ -112,6 +112,11 @@ typedef struct {
|
||||
void* key_data_contents[2];/* Array of pointers */
|
||||
} krb5_key_data;
|
||||
|
||||
typedef struct _krb5_keysalt {
|
||||
int16_t type;
|
||||
krb5_data data; /* Length, data */
|
||||
} krb5_keysalt;
|
||||
|
||||
typedef struct _krb5_tl_data {
|
||||
struct _krb5_tl_data* tl_data_next;
|
||||
int16_t tl_data_type;
|
||||
@@ -129,6 +134,8 @@ typedef struct _krb5_tl_data {
|
||||
#define KRB5_TL_EXTENSION 0x0008
|
||||
#define KRB5_TL_PKINIT_ACL 0x0009
|
||||
#define KRB5_TL_ALIASES 0x000a
|
||||
#define KRB5_TL_HIST_KVNO_DIFF_CLNT 0x000b
|
||||
#define KRB5_TL_HIST_KVNO_DIFF_SVC 0x000c
|
||||
|
||||
typedef struct _kadm5_principal_ent_t {
|
||||
krb5_principal principal;
|
||||
@@ -193,12 +200,9 @@ typedef struct _kadm5_policy_ent_t {
|
||||
#define KADM5_PRIV_DELETE (1 << 3)
|
||||
#define KADM5_PRIV_LIST (1 << 4)
|
||||
#define KADM5_PRIV_CPW (1 << 5)
|
||||
#define KADM5_PRIV_GET_KEYS (1 << 6)
|
||||
#define KADM5_PRIV_ALL (KADM5_PRIV_GET | KADM5_PRIV_ADD | KADM5_PRIV_MODIFY | KADM5_PRIV_DELETE | KADM5_PRIV_LIST | KADM5_PRIV_CPW)
|
||||
|
||||
typedef struct {
|
||||
int XXX;
|
||||
}krb5_key_salt_tuple;
|
||||
|
||||
typedef struct _kadm5_config_params {
|
||||
uint32_t mask;
|
||||
|
||||
@@ -221,38 +225,4 @@ typedef krb5_error_code kadm5_ret_t;
|
||||
|
||||
#include "kadm5-protos.h"
|
||||
|
||||
#if 0
|
||||
/* unimplemented functions */
|
||||
kadm5_ret_t
|
||||
kadm5_decrypt_key(void *server_handle,
|
||||
kadm5_principal_ent_t entry, int32_t
|
||||
ktype, int32_t stype, int32_t
|
||||
kvno, krb5_keyblock *keyblock,
|
||||
krb5_keysalt *keysalt, int *kvnop);
|
||||
|
||||
kadm5_ret_t
|
||||
kadm5_create_policy(void *server_handle,
|
||||
kadm5_policy_ent_t policy, uint32_t mask);
|
||||
|
||||
kadm5_ret_t
|
||||
kadm5_delete_policy(void *server_handle, char *policy);
|
||||
|
||||
|
||||
kadm5_ret_t
|
||||
kadm5_modify_policy(void *server_handle,
|
||||
kadm5_policy_ent_t policy,
|
||||
uint32_t mask);
|
||||
|
||||
kadm5_ret_t
|
||||
kadm5_get_policy(void *server_handle, char *policy, kadm5_policy_ent_t ent);
|
||||
|
||||
kadm5_ret_t
|
||||
kadm5_get_policies(void *server_handle, char *exp,
|
||||
char ***pols, int *count);
|
||||
|
||||
void
|
||||
kadm5_free_policy_ent(kadm5_policy_ent_t policy);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __KADM5_ADMIN_H__ */
|
||||
|
@@ -38,6 +38,7 @@ RCSID("$Id$");
|
||||
kadm5_ret_t
|
||||
kadm5_c_chpass_principal(void *server_handle,
|
||||
krb5_principal princ,
|
||||
int keepold,
|
||||
const char *password)
|
||||
{
|
||||
kadm5_client_context *context = server_handle;
|
||||
@@ -59,6 +60,7 @@ kadm5_c_chpass_principal(void *server_handle,
|
||||
krb5_store_int32(sp, kadm_chpass);
|
||||
krb5_store_principal(sp, princ);
|
||||
krb5_store_string(sp, password);
|
||||
krb5_store_int32(sp, keepold); /* extension */
|
||||
ret = _kadm5_client_send(context, sp);
|
||||
krb5_storage_free(sp);
|
||||
if (ret)
|
||||
@@ -82,6 +84,7 @@ kadm5_c_chpass_principal(void *server_handle,
|
||||
kadm5_ret_t
|
||||
kadm5_c_chpass_principal_with_key(void *server_handle,
|
||||
krb5_principal princ,
|
||||
int keepold,
|
||||
int n_key_data,
|
||||
krb5_key_data *key_data)
|
||||
{
|
||||
@@ -107,6 +110,7 @@ kadm5_c_chpass_principal_with_key(void *server_handle,
|
||||
krb5_store_int32(sp, n_key_data);
|
||||
for (i = 0; i < n_key_data; ++i)
|
||||
kadm5_store_key_data (sp, &key_data[i]);
|
||||
krb5_store_int32(sp, keepold); /* extension */
|
||||
ret = _kadm5_client_send(context, sp);
|
||||
krb5_storage_free(sp);
|
||||
if (ret)
|
||||
|
@@ -38,6 +38,7 @@ RCSID("$Id$");
|
||||
static kadm5_ret_t
|
||||
change(void *server_handle,
|
||||
krb5_principal princ,
|
||||
int keepold,
|
||||
const char *password,
|
||||
int cond)
|
||||
{
|
||||
@@ -49,15 +50,27 @@ change(void *server_handle,
|
||||
int existsp = 0;
|
||||
|
||||
memset(&ent, 0, sizeof(ent));
|
||||
ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
|
||||
if(ret)
|
||||
return ret;
|
||||
if (!context->keep_open) {
|
||||
ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
|
||||
if(ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = context->db->hdb_fetch_kvno(context->context, context->db, princ,
|
||||
HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
|
||||
if(ret)
|
||||
goto out;
|
||||
|
||||
if (keepold || cond) {
|
||||
/*
|
||||
* We save these for now so we can handle password history checking;
|
||||
* we handle keepold further below.
|
||||
*/
|
||||
ret = hdb_add_current_keys_to_history(context->context, &ent.entry);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (context->db->hdb_capability_flags & HDB_CAP_F_HANDLE_PASSWORDS) {
|
||||
ret = context->db->hdb_password(context->context, context->db,
|
||||
&ent, password, cond);
|
||||
@@ -73,15 +86,20 @@ change(void *server_handle,
|
||||
|
||||
ret = _kadm5_set_keys(context, &ent.entry, password);
|
||||
if(ret) {
|
||||
_kadm5_free_keys (context->context, num_keys, keys);
|
||||
_kadm5_free_keys(context->context, num_keys, keys);
|
||||
goto out2;
|
||||
}
|
||||
_kadm5_free_keys(context->context, num_keys, keys);
|
||||
|
||||
if (cond)
|
||||
existsp = _kadm5_exists_keys (ent.entry.keys.val,
|
||||
ent.entry.keys.len,
|
||||
keys, num_keys);
|
||||
_kadm5_free_keys (context->context, num_keys, keys);
|
||||
if (cond) {
|
||||
HDB_extension *ext;
|
||||
|
||||
ext = hdb_find_extension(&ent.entry, choice_HDB_extension_data_hist_keys);
|
||||
if (ext != NULL)
|
||||
existsp = _kadm5_exists_keys_hist(ent.entry.keys.val,
|
||||
ent.entry.keys.len,
|
||||
&ext->data.u.hist_keys);
|
||||
}
|
||||
|
||||
if (existsp) {
|
||||
ret = KADM5_PASS_REUSE;
|
||||
@@ -89,12 +107,23 @@ change(void *server_handle,
|
||||
"Password reuse forbidden");
|
||||
goto out2;
|
||||
}
|
||||
}
|
||||
ent.entry.kvno++;
|
||||
|
||||
if (keepold) {
|
||||
ret = hdb_seal_keys(context->context, context->db, &ent.entry);
|
||||
if (ret)
|
||||
goto out2;
|
||||
} else {
|
||||
HDB_extension ext;
|
||||
|
||||
ext.data.element = choice_HDB_extension_data_hist_keys;
|
||||
ext.data.u.hist_keys.len = 0;
|
||||
ext.data.u.hist_keys.val = NULL;
|
||||
ret = hdb_replace_extension(context->context, &ent.entry, &ext);
|
||||
if (ret)
|
||||
goto out2;
|
||||
}
|
||||
ent.entry.kvno++;
|
||||
|
||||
ret = _kadm5_set_modifier(context, &ent.entry);
|
||||
if(ret)
|
||||
@@ -118,7 +147,8 @@ change(void *server_handle,
|
||||
out2:
|
||||
hdb_free_entry(context->context, &ent);
|
||||
out:
|
||||
context->db->hdb_close(context->context, context->db);
|
||||
if (!context->keep_open)
|
||||
context->db->hdb_close(context->context, context->db);
|
||||
return _kadm5_error_code(ret);
|
||||
}
|
||||
|
||||
@@ -131,9 +161,10 @@ out:
|
||||
kadm5_ret_t
|
||||
kadm5_s_chpass_principal_cond(void *server_handle,
|
||||
krb5_principal princ,
|
||||
int keepold,
|
||||
const char *password)
|
||||
{
|
||||
return change (server_handle, princ, password, 1);
|
||||
return change (server_handle, princ, keepold, password, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -143,9 +174,10 @@ kadm5_s_chpass_principal_cond(void *server_handle,
|
||||
kadm5_ret_t
|
||||
kadm5_s_chpass_principal(void *server_handle,
|
||||
krb5_principal princ,
|
||||
int keepold,
|
||||
const char *password)
|
||||
{
|
||||
return change (server_handle, princ, password, 0);
|
||||
return change (server_handle, princ, keepold, password, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -155,6 +187,7 @@ kadm5_s_chpass_principal(void *server_handle,
|
||||
kadm5_ret_t
|
||||
kadm5_s_chpass_principal_with_key(void *server_handle,
|
||||
krb5_principal princ,
|
||||
int keepold,
|
||||
int n_key_data,
|
||||
krb5_key_data *key_data)
|
||||
{
|
||||
@@ -163,13 +196,20 @@ kadm5_s_chpass_principal_with_key(void *server_handle,
|
||||
kadm5_ret_t ret;
|
||||
|
||||
memset(&ent, 0, sizeof(ent));
|
||||
ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
|
||||
if(ret)
|
||||
return ret;
|
||||
if (!context->keep_open) {
|
||||
ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
|
||||
if(ret)
|
||||
return ret;
|
||||
}
|
||||
ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, 0,
|
||||
HDB_F_GET_ANY|HDB_F_ADMIN_DATA, &ent);
|
||||
if(ret == HDB_ERR_NOENTRY)
|
||||
goto out;
|
||||
if (keepold) {
|
||||
ret = hdb_add_current_keys_to_history(context->context, &ent.entry);
|
||||
if (ret)
|
||||
goto out2;
|
||||
}
|
||||
ret = _kadm5_set_keys2(context, &ent.entry, n_key_data, key_data);
|
||||
if(ret)
|
||||
goto out2;
|
||||
@@ -181,9 +221,19 @@ kadm5_s_chpass_principal_with_key(void *server_handle,
|
||||
if (ret)
|
||||
goto out2;
|
||||
|
||||
ret = hdb_seal_keys(context->context, context->db, &ent.entry);
|
||||
if (ret)
|
||||
goto out2;
|
||||
if (keepold) {
|
||||
ret = hdb_seal_keys(context->context, context->db, &ent.entry);
|
||||
if (ret)
|
||||
goto out2;
|
||||
} else {
|
||||
HDB_extension ext;
|
||||
|
||||
ext.data.element = choice_HDB_extension_data_hist_keys;
|
||||
ext.data.u.hist_keys.len = 0;
|
||||
ext.data.u.hist_keys.val = NULL;
|
||||
hdb_replace_extension(context->context, &ent.entry, &ext);
|
||||
}
|
||||
|
||||
|
||||
ret = context->db->hdb_store(context->context, context->db,
|
||||
HDB_F_REPLACE, &ent);
|
||||
@@ -199,6 +249,7 @@ kadm5_s_chpass_principal_with_key(void *server_handle,
|
||||
out2:
|
||||
hdb_free_entry(context->context, &ent);
|
||||
out:
|
||||
context->db->hdb_close(context->context, context->db);
|
||||
if (!context->keep_open)
|
||||
context->db->hdb_close(context->context, context->db);
|
||||
return _kadm5_error_code(ret);
|
||||
}
|
||||
|
@@ -42,7 +42,25 @@ kadm5_chpass_principal(void *server_handle,
|
||||
krb5_principal princ,
|
||||
const char *password)
|
||||
{
|
||||
return __CALL(chpass_principal, (server_handle, princ, password));
|
||||
return __CALL(chpass_principal, (server_handle, princ, 0, password));
|
||||
}
|
||||
|
||||
kadm5_ret_t
|
||||
kadm5_chpass_principal_3(void *server_handle,
|
||||
krb5_principal princ,
|
||||
krb5_boolean keepold,
|
||||
int n_ks_tuple,
|
||||
krb5_key_salt_tuple *ks_tuple,
|
||||
const char *password)
|
||||
{
|
||||
/*
|
||||
* We should get around to implementing this... This can be useful
|
||||
* for, e.g., x-realm principals. For now we need the _3() to get
|
||||
* certain applications written to the kadm5 API to build and run.
|
||||
*/
|
||||
if (n_ks_tuple > 0)
|
||||
return KADM5_KS_TUPLE_NOSUPP;
|
||||
return __CALL(chpass_principal, (server_handle, princ, keepold, password));
|
||||
}
|
||||
|
||||
kadm5_ret_t
|
||||
@@ -52,7 +70,18 @@ kadm5_chpass_principal_with_key(void *server_handle,
|
||||
krb5_key_data *key_data)
|
||||
{
|
||||
return __CALL(chpass_principal_with_key,
|
||||
(server_handle, princ, n_key_data, key_data));
|
||||
(server_handle, princ, 0, n_key_data, key_data));
|
||||
}
|
||||
|
||||
kadm5_ret_t
|
||||
kadm5_chpass_principal_with_key_3(void *server_handle,
|
||||
krb5_principal princ,
|
||||
int keepold,
|
||||
int n_key_data,
|
||||
krb5_key_data *key_data)
|
||||
{
|
||||
return __CALL(chpass_principal_with_key,
|
||||
(server_handle, princ, keepold, n_key_data, key_data));
|
||||
}
|
||||
|
||||
kadm5_ret_t
|
||||
@@ -92,6 +121,49 @@ kadm5_get_principal(void *server_handle,
|
||||
return __CALL(get_principal, (server_handle, princ, out, mask));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract decrypted keys from kadm5_principal_ent_t object. Mostly a
|
||||
* no-op for Heimdal because we fetch the entry with decrypted keys.
|
||||
* Sadly this is not fully a no-op, as we have to allocate a copy.
|
||||
*
|
||||
* @server_handle is the kadm5 handle
|
||||
* @entry is the HDB entry for the principal in question
|
||||
* @ktype is the enctype to get a key for, or -1 to get the first one
|
||||
* @stype is the salttype to get a key for, or -1 to get the first match
|
||||
* @kvno is the kvno to search for, or -1 to get the first match (highest kvno)
|
||||
* @keyblock is where the key will be placed
|
||||
* @keysalt, if not NULL, is where the salt will be placed
|
||||
* @kvnop, if not NULL, is where the selected kvno will be placed
|
||||
*/
|
||||
kadm5_ret_t
|
||||
kadm5_decrypt_key(void *server_handle,
|
||||
kadm5_principal_ent_t entry,
|
||||
int32_t ktype, int32_t stype,
|
||||
int32_t kvno, krb5_keyblock *keyblock,
|
||||
krb5_keysalt *keysalt, int *kvnop)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (kvno < 1 || stype != -1)
|
||||
return KADM5_DECRYPT_USAGE_NOSUPP;
|
||||
|
||||
for (i = 0; i < entry->n_key_data; i++) {
|
||||
if (ktype != entry->key_data[i].key_data_kvno)
|
||||
continue;
|
||||
|
||||
keyblock->keytype = ktype;
|
||||
keyblock->keyvalue.length = entry->key_data[i].key_data_length[0];
|
||||
keyblock->keyvalue.data = malloc(keyblock->keyvalue.length);
|
||||
if (keyblock->keyvalue.data == NULL)
|
||||
return ENOMEM;
|
||||
memcpy(keyblock->keyvalue.data,
|
||||
entry->key_data[i].key_data_contents[0],
|
||||
keyblock->keyvalue.length);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
kadm5_ret_t
|
||||
kadm5_modify_principal(void *server_handle,
|
||||
kadm5_principal_ent_t princ,
|
||||
@@ -106,7 +178,21 @@ kadm5_randkey_principal(void *server_handle,
|
||||
krb5_keyblock **new_keys,
|
||||
int *n_keys)
|
||||
{
|
||||
return __CALL(randkey_principal, (server_handle, princ, new_keys, n_keys));
|
||||
return __CALL(randkey_principal, (server_handle, princ, FALSE, 0, NULL,
|
||||
new_keys, n_keys));
|
||||
}
|
||||
|
||||
kadm5_ret_t
|
||||
kadm5_randkey_principal_3(void *server_handle,
|
||||
krb5_principal princ,
|
||||
krb5_boolean keepold,
|
||||
int n_ks_tuple,
|
||||
krb5_key_salt_tuple *ks_tuple,
|
||||
krb5_keyblock **new_keys,
|
||||
int *n_keys)
|
||||
{
|
||||
return __CALL(randkey_principal, (server_handle, princ, keepold,
|
||||
n_ks_tuple, ks_tuple, new_keys, n_keys));
|
||||
}
|
||||
|
||||
kadm5_ret_t
|
||||
@@ -132,3 +218,188 @@ kadm5_get_privs(void *server_handle,
|
||||
{
|
||||
return __CALL(get_privs, (server_handle, privs));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function is allows the caller to set new keys for a principal.
|
||||
* This is a trivial wrapper around kadm5_setkey_principal_3().
|
||||
*/
|
||||
kadm5_ret_t
|
||||
kadm5_setkey_principal(void *server_handle,
|
||||
krb5_principal princ,
|
||||
krb5_keyblock *new_keys,
|
||||
int n_keys)
|
||||
{
|
||||
return kadm5_setkey_principal_3(server_handle, princ, 0, 0, NULL,
|
||||
new_keys, n_keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is allows the caller to set new keys for a principal.
|
||||
* This is a simple wrapper around kadm5_get_principal() and
|
||||
* kadm5_modify_principal().
|
||||
*/
|
||||
kadm5_ret_t
|
||||
kadm5_setkey_principal_3(void *server_handle,
|
||||
krb5_principal princ,
|
||||
krb5_boolean keepold,
|
||||
int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
|
||||
krb5_keyblock *keyblocks,
|
||||
int n_keys)
|
||||
{
|
||||
kadm5_principal_ent_rec princ_ent;
|
||||
kadm5_ret_t ret;
|
||||
krb5_key_data *new_key_data = NULL;
|
||||
size_t i;
|
||||
|
||||
if (n_keys < 1)
|
||||
return EINVAL;
|
||||
if (n_ks_tuple > 0 && n_ks_tuple != n_keys)
|
||||
return KADM5_SETKEY3_ETYPE_MISMATCH;
|
||||
|
||||
ret = kadm5_get_principal(server_handle, princ, &princ_ent,
|
||||
KADM5_KVNO | KADM5_PRINCIPAL | KADM5_KEY_DATA);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (keepold) {
|
||||
new_key_data = malloc((n_keys + princ_ent.n_key_data) * sizeof(*new_key_data));
|
||||
if (new_key_data == NULL) {
|
||||
ret = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(&new_key_data[n_keys], &princ_ent.key_data[0],
|
||||
princ_ent.n_key_data * sizeof (princ_ent.key_data[0]));
|
||||
} else {
|
||||
new_key_data = malloc(n_keys * sizeof(*new_key_data));
|
||||
if (new_key_data == NULL) {
|
||||
ret = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
princ_ent.kvno++;
|
||||
for (i = 0; i < n_keys; i++) {
|
||||
new_key_data[i].key_data_ver = 2;
|
||||
|
||||
/* Key */
|
||||
new_key_data[i].key_data_kvno = princ_ent.kvno;
|
||||
new_key_data[i].key_data_type[0] = keyblocks[i].keytype;
|
||||
new_key_data[i].key_data_length[0] = keyblocks[i].keyvalue.length;
|
||||
new_key_data[i].key_data_contents[0] =
|
||||
malloc(keyblocks[i].keyvalue.length);
|
||||
if (new_key_data[i].key_data_contents[0] == NULL) {
|
||||
ret = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
memcpy(new_key_data[i].key_data_contents[0],
|
||||
keyblocks[i].keyvalue.data,
|
||||
keyblocks[i].keyvalue.length);
|
||||
|
||||
/*
|
||||
* Salt (but there's no salt, just salttype, which is kinda
|
||||
* silly -- what's the point of setkey_3() then, besides
|
||||
* keepold?!)
|
||||
*/
|
||||
new_key_data[i].key_data_type[1] = 0;
|
||||
if (n_ks_tuple > 0) {
|
||||
if (ks_tuple[i].ks_enctype != keyblocks[i].keytype)
|
||||
return KADM5_SETKEY3_ETYPE_MISMATCH;
|
||||
new_key_data[i].key_data_type[1] = ks_tuple[i].ks_salttype;
|
||||
}
|
||||
new_key_data[i].key_data_length[1] = 0;
|
||||
new_key_data[i].key_data_contents[1] = NULL;
|
||||
}
|
||||
|
||||
/* Free old keys */
|
||||
if (!keepold) {
|
||||
for (i = 0; i < princ_ent.n_key_data; i++) {
|
||||
free(princ_ent.key_data[i].key_data_contents[0]);
|
||||
free(princ_ent.key_data[i].key_data_contents[1]);
|
||||
}
|
||||
}
|
||||
free(princ_ent.key_data);
|
||||
princ_ent.key_data = new_key_data;
|
||||
princ_ent.n_key_data = n_keys + (keepold ? princ_ent.n_key_data : 0);
|
||||
new_key_data = NULL;
|
||||
|
||||
/* Modify the principal */
|
||||
ret = kadm5_modify_principal(server_handle, &princ_ent, KADM5_KVNO | KADM5_KEY_DATA);
|
||||
|
||||
out:
|
||||
if (new_key_data != NULL) {
|
||||
for (i = 0; i < n_keys; i++) {
|
||||
free(new_key_data[i].key_data_contents[0]);
|
||||
free(new_key_data[i].key_data_contents[1]);
|
||||
}
|
||||
free(new_key_data);
|
||||
}
|
||||
kadm5_free_principal_ent(server_handle, &princ_ent);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
kadm5_ret_t
|
||||
kadm5_lock(void *server_handle)
|
||||
{
|
||||
return __CALL(lock, (server_handle));
|
||||
}
|
||||
|
||||
kadm5_ret_t
|
||||
kadm5_unlock(void *server_handle)
|
||||
{
|
||||
return __CALL(unlock, (server_handle));
|
||||
}
|
||||
|
||||
|
||||
kadm5_ret_t
|
||||
kadm5_create_policy(void *server_handle,
|
||||
kadm5_policy_ent_t policy, long mask)
|
||||
{
|
||||
return KADM5_POLICY_OP_NOSUPP;
|
||||
}
|
||||
|
||||
kadm5_ret_t
|
||||
kadm5_delete_policy(void *server_handle, char *name)
|
||||
{
|
||||
return KADM5_POLICY_OP_NOSUPP;
|
||||
}
|
||||
|
||||
|
||||
kadm5_ret_t
|
||||
kadm5_modify_policy(void *server_handle, kadm5_policy_ent_t policy,
|
||||
uint32_t mask)
|
||||
{
|
||||
return KADM5_POLICY_OP_NOSUPP;
|
||||
}
|
||||
|
||||
kadm5_ret_t
|
||||
kadm5_get_policy(void *server_handle, char *policy, kadm5_policy_ent_t ent)
|
||||
{
|
||||
memset(ent, 0, sizeof (*ent));
|
||||
return KADM5_POLICY_OP_NOSUPP;
|
||||
}
|
||||
|
||||
|
||||
kadm5_ret_t
|
||||
kadm5_get_policies(void *server_handle, char *exp, char ***pols, int *count)
|
||||
{
|
||||
*count = 0;
|
||||
*pols = NULL;
|
||||
|
||||
return KADM5_POLICY_OP_NOSUPP;
|
||||
}
|
||||
|
||||
kadm5_ret_t
|
||||
kadm5_free_policy_ent(kadm5_policy_ent_t ent)
|
||||
{
|
||||
if (ent->policy)
|
||||
free(ent->policy);
|
||||
/*
|
||||
* Not clear if we should free ent or not. It might be an automatic
|
||||
* struct, so we don't free it for now, just in case.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -35,6 +35,53 @@
|
||||
|
||||
RCSID("$Id$");
|
||||
|
||||
static kadm5_ret_t
|
||||
kadm5_s_lock(void *server_handle)
|
||||
{
|
||||
kadm5_server_context *context = server_handle;
|
||||
kadm5_ret_t ret;
|
||||
|
||||
if (context->keep_open) {
|
||||
/*
|
||||
* We open/close around every operation, but we retain the DB
|
||||
* open if the DB was locked with a prior call to kadm5_lock(),
|
||||
* so if it's open here that must be because the DB is locked.
|
||||
*/
|
||||
heim_assert(context->db->lock_count > 0,
|
||||
"Internal error in tracking HDB locks");
|
||||
return KADM5_ALREADY_LOCKED;
|
||||
}
|
||||
|
||||
ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = context->db->hdb_lock(context->context, context->db, HDB_WLOCK);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
context->keep_open = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static kadm5_ret_t
|
||||
kadm5_s_unlock(void *server_handle)
|
||||
{
|
||||
kadm5_server_context *context = server_handle;
|
||||
kadm5_ret_t ret;
|
||||
|
||||
if (!context->keep_open)
|
||||
return KADM5_NOT_LOCKED;
|
||||
|
||||
(void) context->db->hdb_close(context->context, context->db);
|
||||
|
||||
context->keep_open = 0;
|
||||
ret = context->db->hdb_unlock(context->context, context->db);
|
||||
if (ret)
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
set_funcs(kadm5_server_context *c)
|
||||
{
|
||||
@@ -51,6 +98,8 @@ set_funcs(kadm5_server_context *c)
|
||||
SET(c, modify_principal);
|
||||
SET(c, randkey_principal);
|
||||
SET(c, rename_principal);
|
||||
SET(c, lock);
|
||||
SET(c, unlock);
|
||||
}
|
||||
|
||||
#ifndef NO_UNIX_SOCKETS
|
||||
|
@@ -65,6 +65,7 @@ create_principal(kadm5_server_context *context,
|
||||
kadm5_principal_ent_rec defrec, *defent;
|
||||
uint32_t def_mask;
|
||||
|
||||
memset(ent, 0, sizeof(*ent));
|
||||
if((mask & required_mask) != required_mask)
|
||||
return KADM5_BAD_MASK;
|
||||
if((mask & forbidden_mask))
|
||||
@@ -72,7 +73,6 @@ create_principal(kadm5_server_context *context,
|
||||
if((mask & KADM5_POLICY) && strcmp(princ->policy, "default"))
|
||||
/* XXX no real policies for now */
|
||||
return KADM5_UNK_POLICY;
|
||||
memset(ent, 0, sizeof(*ent));
|
||||
ret = krb5_copy_principal(context->context, princ->principal,
|
||||
&ent->entry.principal);
|
||||
if(ret)
|
||||
@@ -111,6 +111,12 @@ kadm5_s_create_principal_with_key(void *server_handle,
|
||||
hdb_entry_ex ent;
|
||||
kadm5_server_context *context = server_handle;
|
||||
|
||||
if ((mask & KADM5_KVNO) == 0) {
|
||||
/* create_principal() through _kadm5_setup_entry(), will need this */
|
||||
princ->kvno = 1;
|
||||
mask |= KADM5_KVNO;
|
||||
}
|
||||
|
||||
ret = create_principal(context, princ, mask, &ent,
|
||||
KADM5_PRINCIPAL | KADM5_KEY_DATA,
|
||||
KADM5_LAST_PWD_CHANGE | KADM5_MOD_TIME
|
||||
@@ -121,18 +127,18 @@ kadm5_s_create_principal_with_key(void *server_handle,
|
||||
if(ret)
|
||||
goto out;
|
||||
|
||||
if ((mask & KADM5_KVNO) == 0)
|
||||
ent.entry.kvno = 1;
|
||||
|
||||
ret = hdb_seal_keys(context->context, context->db, &ent.entry);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
|
||||
if(ret)
|
||||
goto out;
|
||||
if (!context->keep_open) {
|
||||
ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
|
||||
if(ret)
|
||||
goto out;
|
||||
}
|
||||
ret = context->db->hdb_store(context->context, context->db, 0, &ent);
|
||||
context->db->hdb_close(context->context, context->db);
|
||||
if (!context->keep_open)
|
||||
context->db->hdb_close(context->context, context->db);
|
||||
if (ret)
|
||||
goto out;
|
||||
kadm5_log_create (context, &ent.entry);
|
||||
@@ -153,6 +159,12 @@ kadm5_s_create_principal(void *server_handle,
|
||||
hdb_entry_ex ent;
|
||||
kadm5_server_context *context = server_handle;
|
||||
|
||||
if ((mask & KADM5_KVNO) == 0) {
|
||||
/* create_principal() through _kadm5_setup_entry(), will need this */
|
||||
princ->kvno = 1;
|
||||
mask |= KADM5_KVNO;
|
||||
}
|
||||
|
||||
ret = create_principal(context, princ, mask, &ent,
|
||||
KADM5_PRINCIPAL,
|
||||
KADM5_LAST_PWD_CHANGE | KADM5_MOD_TIME
|
||||
@@ -163,9 +175,6 @@ kadm5_s_create_principal(void *server_handle,
|
||||
if(ret)
|
||||
goto out;
|
||||
|
||||
if ((mask & KADM5_KVNO) == 0)
|
||||
ent.entry.kvno = 1;
|
||||
|
||||
ent.entry.keys.len = 0;
|
||||
ent.entry.keys.val = NULL;
|
||||
|
||||
@@ -177,11 +186,14 @@ kadm5_s_create_principal(void *server_handle,
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
|
||||
if(ret)
|
||||
goto out;
|
||||
if (!context->keep_open) {
|
||||
ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
|
||||
if(ret)
|
||||
goto out;
|
||||
}
|
||||
ret = context->db->hdb_store(context->context, context->db, 0, &ent);
|
||||
context->db->hdb_close(context->context, context->db);
|
||||
if (!context->keep_open)
|
||||
context->db->hdb_close(context->context, context->db);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
|
@@ -85,7 +85,8 @@ parse_file(krb5_context context, krb5_principal principal, int no_salt)
|
||||
size_t nkeys;
|
||||
Key *keys;
|
||||
|
||||
ret = hdb_generate_key_set(context, principal, &keys, &nkeys, no_salt);
|
||||
ret = hdb_generate_key_set(context, principal, 0, NULL, &keys, &nkeys,
|
||||
no_salt);
|
||||
if (ret)
|
||||
krb5_err(context, 1, ret, "hdb_generate_key_set");
|
||||
|
||||
|
@@ -43,10 +43,12 @@ kadm5_s_delete_principal(void *server_handle, krb5_principal princ)
|
||||
hdb_entry_ex ent;
|
||||
|
||||
memset(&ent, 0, sizeof(ent));
|
||||
ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
|
||||
if(ret) {
|
||||
krb5_warn(context->context, ret, "opening database");
|
||||
return ret;
|
||||
if (!context->keep_open) {
|
||||
ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
|
||||
if(ret) {
|
||||
krb5_warn(context->context, ret, "opening database");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret = context->db->hdb_fetch_kvno(context->context, context->db, princ,
|
||||
HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
|
||||
@@ -70,6 +72,7 @@ kadm5_s_delete_principal(void *server_handle, krb5_principal princ)
|
||||
out2:
|
||||
hdb_free_entry(context->context, &ent);
|
||||
out:
|
||||
context->db->hdb_close(context->context, context->db);
|
||||
if (!context->keep_open)
|
||||
context->db->hdb_close(context->context, context->db);
|
||||
return _kadm5_error_code(ret);
|
||||
}
|
||||
|
@@ -178,8 +178,27 @@ _kadm5_setup_entry(kadm5_server_context *context,
|
||||
}
|
||||
}
|
||||
if(mask & KADM5_KVNO
|
||||
&& princ_mask & KADM5_KVNO)
|
||||
ent->entry.kvno = princ->kvno;
|
||||
&& princ_mask & KADM5_KVNO) {
|
||||
/*
|
||||
* For some reason kadmin's ank changes the kvno after calling
|
||||
* randkey. Now that we have key history, what are we to do
|
||||
* when we update kvno but not keys?!
|
||||
*
|
||||
* For now just clear the key history if the kvno changes.
|
||||
* Eventually we may want to search the key history for matching
|
||||
* keys and use those to replace the current key set (putting
|
||||
* the old current keyset in the history keysets list?!).
|
||||
*/
|
||||
if (ent->entry.kvno != princ->kvno &&
|
||||
(mask & princ_mask & KADM5_KEY_DATA)) {
|
||||
hdb_clear_extension(context->context, &ent->entry,
|
||||
choice_HDB_extension_data_hist_keys);
|
||||
princ->kvno = ent->entry.kvno;
|
||||
} else {
|
||||
/* _kadm5_set_keys2() expects this to have been done here */
|
||||
ent->entry.kvno = princ->kvno;
|
||||
}
|
||||
}
|
||||
if(mask & KADM5_MAX_RLIFE) {
|
||||
if(princ_mask & KADM5_MAX_RLIFE) {
|
||||
if(princ->max_renewable_life)
|
||||
|
@@ -85,10 +85,13 @@ kadm5_s_get_principals(void *server_handle,
|
||||
struct foreach_data d;
|
||||
kadm5_server_context *context = server_handle;
|
||||
kadm5_ret_t ret;
|
||||
ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
|
||||
if(ret) {
|
||||
krb5_warn(context->context, ret, "opening database");
|
||||
return ret;
|
||||
|
||||
if (!context->keep_open) {
|
||||
ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
|
||||
if(ret) {
|
||||
krb5_warn(context->context, ret, "opening database");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
d.exp = expression;
|
||||
{
|
||||
@@ -100,7 +103,8 @@ kadm5_s_get_principals(void *server_handle,
|
||||
d.princs = NULL;
|
||||
d.count = 0;
|
||||
ret = hdb_foreach(context->context, context->db, HDB_F_ADMIN_DATA, foreach, &d);
|
||||
context->db->hdb_close(context->context, context->db);
|
||||
if (!context->keep_open)
|
||||
context->db->hdb_close(context->context, context->db);
|
||||
if(ret == 0)
|
||||
ret = add_princ(&d, NULL);
|
||||
if(ret == 0){
|
||||
|
@@ -32,6 +32,7 @@
|
||||
*/
|
||||
|
||||
#include "kadm5_locl.h"
|
||||
#include <assert.h>
|
||||
|
||||
RCSID("$Id$");
|
||||
|
||||
@@ -64,6 +65,57 @@ add_tl_data(kadm5_principal_ent_t ent, int16_t type,
|
||||
KRB5_LIB_FUNCTION krb5_ssize_t KRB5_LIB_CALL
|
||||
_krb5_put_int(void *buffer, unsigned long value, size_t size); /* XXX */
|
||||
|
||||
static
|
||||
krb5_error_code
|
||||
copy_keyset_to_kadm5(kadm5_server_context *context, krb5_kvno kvno,
|
||||
size_t n_keys, Key *keys, krb5_salt *salt,
|
||||
kadm5_principal_ent_t out)
|
||||
{
|
||||
size_t i;
|
||||
Key *key;
|
||||
krb5_key_data *kd;
|
||||
krb5_data *sp;
|
||||
krb5_error_code ret = 0;
|
||||
|
||||
for (i = 0; i < n_keys; i++) {
|
||||
key = &keys[i];
|
||||
kd = &out->key_data[out->n_key_data];
|
||||
kd->key_data_ver = 2;
|
||||
kd->key_data_kvno = kvno;
|
||||
kd->key_data_type[0] = key->key.keytype;
|
||||
if(key->salt)
|
||||
kd->key_data_type[1] = key->salt->type;
|
||||
else
|
||||
kd->key_data_type[1] = KRB5_PADATA_PW_SALT;
|
||||
/* setup key */
|
||||
kd->key_data_length[0] = key->key.keyvalue.length;
|
||||
kd->key_data_contents[0] = malloc(kd->key_data_length[0]);
|
||||
if(kd->key_data_contents[0] == NULL && kd->key_data_length[0] != 0){
|
||||
ret = ENOMEM;
|
||||
break;
|
||||
}
|
||||
memcpy(kd->key_data_contents[0], key->key.keyvalue.data,
|
||||
kd->key_data_length[0]);
|
||||
/* setup salt */
|
||||
if(key->salt)
|
||||
sp = &key->salt->salt;
|
||||
else
|
||||
sp = &salt->saltvalue;
|
||||
kd->key_data_length[1] = sp->length;
|
||||
kd->key_data_contents[1] = malloc(kd->key_data_length[1]);
|
||||
if(kd->key_data_length[1] != 0
|
||||
&& kd->key_data_contents[1] == NULL) {
|
||||
memset(kd->key_data_contents[0], 0, kd->key_data_length[0]);
|
||||
ret = ENOMEM;
|
||||
break;
|
||||
}
|
||||
memcpy(kd->key_data_contents[1], sp->data, kd->key_data_length[1]);
|
||||
out->n_key_data++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
kadm5_ret_t
|
||||
kadm5_s_get_principal(void *server_handle,
|
||||
krb5_principal princ,
|
||||
@@ -75,12 +127,17 @@ kadm5_s_get_principal(void *server_handle,
|
||||
hdb_entry_ex ent;
|
||||
|
||||
memset(&ent, 0, sizeof(ent));
|
||||
ret = context->db->hdb_open(context->context, context->db, O_RDONLY, 0);
|
||||
if(ret)
|
||||
return ret;
|
||||
|
||||
if (!context->keep_open) {
|
||||
ret = context->db->hdb_open(context->context, context->db, O_RDONLY, 0);
|
||||
if(ret)
|
||||
return ret;
|
||||
}
|
||||
ret = context->db->hdb_fetch_kvno(context->context, context->db, princ,
|
||||
HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
|
||||
context->db->hdb_close(context->context, context->db);
|
||||
HDB_F_DECRYPT|HDB_F_ALL_KVNOS|
|
||||
HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
|
||||
if (!context->keep_open)
|
||||
context->db->hdb_close(context->context, context->db);
|
||||
if(ret)
|
||||
return _kadm5_error_code(ret);
|
||||
|
||||
@@ -160,8 +217,21 @@ kadm5_s_get_principal(void *server_handle,
|
||||
if(mask & KADM5_FAIL_AUTH_COUNT)
|
||||
;
|
||||
#endif
|
||||
if(mask & KADM5_POLICY)
|
||||
out->policy = NULL;
|
||||
if(mask & KADM5_POLICY) {
|
||||
HDB_extension *ext;
|
||||
|
||||
ext = hdb_find_extension(&ent.entry, choice_HDB_extension_data_policy);
|
||||
if (ext == NULL) {
|
||||
out->policy = strdup("default");
|
||||
/* It's OK if we retun NULL instead of "default" */
|
||||
} else {
|
||||
out->policy = strdup(ext->data.u.policy);
|
||||
if (out->policy == NULL) {
|
||||
ret = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(mask & KADM5_MAX_RLIFE) {
|
||||
if(ent.entry.max_renew)
|
||||
out->max_renewable_life = *ent.entry.max_renew;
|
||||
@@ -170,52 +240,38 @@ kadm5_s_get_principal(void *server_handle,
|
||||
}
|
||||
if(mask & KADM5_KEY_DATA){
|
||||
size_t i;
|
||||
Key *key;
|
||||
krb5_key_data *kd;
|
||||
size_t n_keys = ent.entry.keys.len;
|
||||
krb5_salt salt;
|
||||
krb5_data *sp;
|
||||
HDB_extension *ext;
|
||||
HDB_Ext_KeySet *hist_keys = NULL;
|
||||
|
||||
ext = hdb_find_extension(&ent.entry, choice_HDB_extension_data_hist_keys);
|
||||
if (ext != NULL)
|
||||
hist_keys = &ext->data.u.hist_keys;
|
||||
|
||||
krb5_get_pw_salt(context->context, ent.entry.principal, &salt);
|
||||
out->key_data = malloc(ent.entry.keys.len * sizeof(*out->key_data));
|
||||
if (out->key_data == NULL && ent.entry.keys.len != 0) {
|
||||
for (i = 0; hist_keys != NULL && i < hist_keys->len; i++)
|
||||
n_keys += hist_keys->val[i].keys.len;
|
||||
out->key_data = malloc(n_keys * sizeof(*out->key_data));
|
||||
if (out->key_data == NULL && n_keys != 0) {
|
||||
ret = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
for(i = 0; i < ent.entry.keys.len; i++){
|
||||
key = &ent.entry.keys.val[i];
|
||||
kd = &out->key_data[i];
|
||||
kd->key_data_ver = 2;
|
||||
kd->key_data_kvno = ent.entry.kvno;
|
||||
kd->key_data_type[0] = key->key.keytype;
|
||||
if(key->salt)
|
||||
kd->key_data_type[1] = key->salt->type;
|
||||
else
|
||||
kd->key_data_type[1] = KRB5_PADATA_PW_SALT;
|
||||
/* setup key */
|
||||
kd->key_data_length[0] = key->key.keyvalue.length;
|
||||
kd->key_data_contents[0] = malloc(kd->key_data_length[0]);
|
||||
if(kd->key_data_contents[0] == NULL && kd->key_data_length[0] != 0){
|
||||
ret = ENOMEM;
|
||||
break;
|
||||
}
|
||||
memcpy(kd->key_data_contents[0], key->key.keyvalue.data,
|
||||
kd->key_data_length[0]);
|
||||
/* setup salt */
|
||||
if(key->salt)
|
||||
sp = &key->salt->salt;
|
||||
else
|
||||
sp = &salt.saltvalue;
|
||||
kd->key_data_length[1] = sp->length;
|
||||
kd->key_data_contents[1] = malloc(kd->key_data_length[1]);
|
||||
if(kd->key_data_length[1] != 0
|
||||
&& kd->key_data_contents[1] == NULL) {
|
||||
memset(kd->key_data_contents[0], 0, kd->key_data_length[0]);
|
||||
ret = ENOMEM;
|
||||
break;
|
||||
}
|
||||
memcpy(kd->key_data_contents[1], sp->data, kd->key_data_length[1]);
|
||||
out->n_key_data = i + 1;
|
||||
out->n_key_data = 0;
|
||||
ret = copy_keyset_to_kadm5(context, ent.entry.kvno, ent.entry.keys.len,
|
||||
ent.entry.keys.val, &salt, out);
|
||||
if (ret)
|
||||
goto out;
|
||||
for (i = 0; hist_keys != NULL && i < hist_keys->len; i++) {
|
||||
ret = copy_keyset_to_kadm5(context, hist_keys->val[i].kvno,
|
||||
hist_keys->val[i].keys.len,
|
||||
hist_keys->val[i].keys.val,
|
||||
&salt, out);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
krb5_free_salt(context->context, salt);
|
||||
assert( out->n_key_data == n_keys );
|
||||
}
|
||||
if(ret){
|
||||
kadm5_free_principal_ent(context, out);
|
||||
|
@@ -45,6 +45,18 @@
|
||||
|
||||
RCSID("$Id$");
|
||||
|
||||
static kadm5_ret_t
|
||||
kadm5_c_lock(void *server_handle)
|
||||
{
|
||||
return ENOTSUP;
|
||||
}
|
||||
|
||||
static kadm5_ret_t
|
||||
kadm5_c_unlock(void *server_handle)
|
||||
{
|
||||
return ENOTSUP;
|
||||
}
|
||||
|
||||
static void
|
||||
set_funcs(kadm5_client_context *c)
|
||||
{
|
||||
@@ -61,6 +73,8 @@ set_funcs(kadm5_client_context *c)
|
||||
SET(c, modify_principal);
|
||||
SET(c, randkey_principal);
|
||||
SET(c, rename_principal);
|
||||
SET(c, lock);
|
||||
SET(c, unlock);
|
||||
}
|
||||
|
||||
kadm5_ret_t
|
||||
|
@@ -57,3 +57,11 @@ error_code AUTH_CHANGEPW, "Operation requires `change-password' privilege"
|
||||
error_code BAD_TL_TYPE, "Invalid tagged data list element type"
|
||||
error_code MISSING_CONF_PARAMS, "Required parameters in kdc.conf missing"
|
||||
error_code BAD_SERVER_NAME, "Bad krb5 admin server hostname"
|
||||
error_code KS_TUPLE_NOSUPP, "Key/salt tuples not supported by this function"
|
||||
error_code SETKEY3_ETYPE_MISMATCH, "Key/salt tuples don't match keys"
|
||||
error_code DECRYPT_USAGE_NOSUPP, "Given usage of kadm5_decrypt() not supported"
|
||||
error_code POLICY_OP_NOSUPP, "Policy operations not supported"
|
||||
error_code KEEPOLD_NOSUPP, "Keep old keys option not supported"
|
||||
error_code AUTH_GET_KEYS, "Operation requires `get-keys' privilege"
|
||||
error_code ALREADY_LOCKED, "Database already locked"
|
||||
error_code NOT_LOCKED, "Database not locked"
|
||||
|
@@ -38,6 +38,7 @@
|
||||
|
||||
#include <config.h>
|
||||
#include <roken.h>
|
||||
#include <heimbase.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@@ -63,16 +63,18 @@ _kadm5_init_keys (Key *keys, int len)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* return 1 if any key in `keys1, len1' exists in `keys2, len2'
|
||||
*/
|
||||
|
||||
int
|
||||
static int
|
||||
_kadm5_exists_keys(Key *keys1, int len1, Key *keys2, int len2)
|
||||
{
|
||||
int i, j;
|
||||
size_t i, j;
|
||||
size_t optimize;
|
||||
|
||||
for (i = 0; i < len1; ++i) {
|
||||
optimize = 0;
|
||||
for (j = 0; j < len2; j++) {
|
||||
if ((keys1[i].salt != NULL && keys2[j].salt == NULL)
|
||||
|| (keys1[i].salt == NULL && keys2[j].salt != NULL))
|
||||
@@ -89,6 +91,7 @@ _kadm5_exists_keys(Key *keys1, int len1, Key *keys2, int len2)
|
||||
}
|
||||
if (keys1[i].key.keytype != keys2[j].key.keytype)
|
||||
continue;
|
||||
optimize = 1;
|
||||
if (keys1[i].key.keyvalue.length != keys2[j].key.keyvalue.length)
|
||||
continue;
|
||||
if (memcmp (keys1[i].key.keyvalue.data, keys2[j].key.keyvalue.data,
|
||||
@@ -97,6 +100,33 @@ _kadm5_exists_keys(Key *keys1, int len1, Key *keys2, int len2)
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Optimization: no need to check all of keys1[] if one there
|
||||
* was one key in keys2[] with matching enctype and salt but not
|
||||
* matching key. Assumption: all keys in keys1[] and keys2[]
|
||||
* are output by string2key.
|
||||
*/
|
||||
if (optimize)
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* return 1 if any key in `keys1, len1' exists in hist_keys
|
||||
*/
|
||||
int
|
||||
_kadm5_exists_keys_hist(Key *keys1, int len1, HDB_Ext_KeySet *hist_keys)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < hist_keys->len; i++) {
|
||||
if (_kadm5_exists_keys(keys1, len1,
|
||||
hist_keys->val[i].keys.val,
|
||||
hist_keys->val[i].keys.len))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -585,7 +585,8 @@ kadm5_log_replay_modify (kadm5_server_context *context,
|
||||
memset(&ent, 0, sizeof(ent));
|
||||
ret = context->db->hdb_fetch_kvno(context->context, context->db,
|
||||
log_ent.entry.principal,
|
||||
HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
|
||||
HDB_F_DECRYPT|HDB_F_ALL_KVNOS|
|
||||
HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
|
||||
if (ret)
|
||||
goto out;
|
||||
if (mask & KADM5_PRINC_EXPIRE_TIME) {
|
||||
@@ -698,6 +699,29 @@ kadm5_log_replay_modify (kadm5_server_context *context,
|
||||
size_t num;
|
||||
size_t i;
|
||||
|
||||
/*
|
||||
* We don't need to do anything about key history here because
|
||||
* we always log KADM5_TL_DATA when we change keys/passwords, so
|
||||
* the code below this will handle key history implicitly.
|
||||
* However, if we had to, the code to handle key history here
|
||||
* would look like this:
|
||||
*
|
||||
* HDB_extension *ext;
|
||||
* ...
|
||||
* ext = hdb_find_extension(&log_ent.entry,
|
||||
* choice_HDB_extension_data_hist_keys);
|
||||
* if (ext);
|
||||
* ret = hdb_replace_extension(context->context, &ent.entry, ext);
|
||||
* else
|
||||
* ret = hdb_clear_extension(context->context, &ent.entry,
|
||||
* choice_HDB_extension_data_hist_keys);
|
||||
*
|
||||
* Maybe we should do this here anyways, wasteful as it would
|
||||
* be, as a defensive programming measure? For now we heim_assert().
|
||||
*/
|
||||
heim_assert((mask & KADM5_TL_DATA),
|
||||
"Wouldn't log and replay key history");
|
||||
|
||||
for (i = 0; i < ent.entry.keys.len; ++i)
|
||||
free_Key(&ent.entry.keys.val[i]);
|
||||
free (ent.entry.keys.val);
|
||||
|
@@ -53,6 +53,38 @@ kadm5_store_key_data(krb5_storage *sp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
kadm5_ret_t
|
||||
kadm5_store_fake_key_data(krb5_storage *sp,
|
||||
krb5_key_data *key)
|
||||
{
|
||||
char buf[4] = {0};
|
||||
krb5_data c;
|
||||
|
||||
krb5_store_int32(sp, key->key_data_ver);
|
||||
krb5_store_int32(sp, key->key_data_kvno);
|
||||
krb5_store_int32(sp, key->key_data_type[0]);
|
||||
|
||||
/*
|
||||
* This is the key contents. We want it to be obvious to the client
|
||||
* (if it really did want the keys) that the key won't work.
|
||||
* 32-bit keys are no good for any enctype, so that should do.
|
||||
* Clients that didn't need keys will ignore this, and clients that
|
||||
* did want keys will either fail or they'll, say, create bogus
|
||||
* keytab entries that will subsequently fail to be useful.
|
||||
*/
|
||||
c.length = sizeof (buf);
|
||||
c.data = buf;
|
||||
memset(buf, 0xdeadcee5, sizeof (buf)); /* bad bad hexspeak for deadkeys */
|
||||
krb5_store_data(sp, c);
|
||||
|
||||
/* This is the salt -- no need to send garbage */
|
||||
krb5_store_int32(sp, key->key_data_type[1]);
|
||||
c.length = key->key_data_length[1];
|
||||
c.data = key->key_data_contents[1];
|
||||
krb5_store_data(sp, c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
kadm5_ret_t
|
||||
kadm5_ret_key_data(krb5_storage *sp,
|
||||
krb5_key_data *key)
|
||||
@@ -105,7 +137,7 @@ kadm5_ret_tl_data(krb5_storage *sp,
|
||||
static kadm5_ret_t
|
||||
store_principal_ent(krb5_storage *sp,
|
||||
kadm5_principal_ent_t princ,
|
||||
uint32_t mask)
|
||||
uint32_t mask, int wkeys)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -149,8 +181,12 @@ store_principal_ent(krb5_storage *sp,
|
||||
krb5_store_int32(sp, princ->fail_auth_count);
|
||||
if (mask & KADM5_KEY_DATA) {
|
||||
krb5_store_int32(sp, princ->n_key_data);
|
||||
for(i = 0; i < princ->n_key_data; i++)
|
||||
kadm5_store_key_data(sp, &princ->key_data[i]);
|
||||
for(i = 0; i < princ->n_key_data; i++) {
|
||||
if (wkeys)
|
||||
kadm5_store_key_data(sp, &princ->key_data[i]);
|
||||
else
|
||||
kadm5_store_fake_key_data(sp, &princ->key_data[i]);
|
||||
}
|
||||
}
|
||||
if (mask & KADM5_TL_DATA) {
|
||||
krb5_tl_data *tp;
|
||||
@@ -167,7 +203,14 @@ kadm5_ret_t
|
||||
kadm5_store_principal_ent(krb5_storage *sp,
|
||||
kadm5_principal_ent_t princ)
|
||||
{
|
||||
return store_principal_ent (sp, princ, ~0);
|
||||
return store_principal_ent (sp, princ, ~0, 1);
|
||||
}
|
||||
|
||||
kadm5_ret_t
|
||||
kadm5_store_principal_ent_nokeys(krb5_storage *sp,
|
||||
kadm5_principal_ent_t princ)
|
||||
{
|
||||
return store_principal_ent (sp, princ, ~0, 0);
|
||||
}
|
||||
|
||||
kadm5_ret_t
|
||||
@@ -176,7 +219,7 @@ kadm5_store_principal_ent_mask(krb5_storage *sp,
|
||||
uint32_t mask)
|
||||
{
|
||||
krb5_store_int32(sp, mask);
|
||||
return store_principal_ent (sp, princ, mask);
|
||||
return store_principal_ent (sp, princ, mask, 1);
|
||||
}
|
||||
|
||||
static kadm5_ret_t
|
||||
|
@@ -44,15 +44,19 @@ modify_principal(void *server_handle,
|
||||
kadm5_server_context *context = server_handle;
|
||||
hdb_entry_ex ent;
|
||||
kadm5_ret_t ret;
|
||||
|
||||
memset(&ent, 0, sizeof(ent));
|
||||
|
||||
if((mask & forbidden_mask))
|
||||
return KADM5_BAD_MASK;
|
||||
if((mask & KADM5_POLICY) && strcmp(princ->policy, "default"))
|
||||
return KADM5_UNK_POLICY;
|
||||
|
||||
memset(&ent, 0, sizeof(ent));
|
||||
ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
|
||||
if(ret)
|
||||
return ret;
|
||||
if (!context->keep_open) {
|
||||
ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
|
||||
if(ret)
|
||||
return ret;
|
||||
}
|
||||
ret = context->db->hdb_fetch_kvno(context->context, context->db,
|
||||
princ->principal, HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
|
||||
if(ret)
|
||||
@@ -68,6 +72,21 @@ modify_principal(void *server_handle,
|
||||
if (ret)
|
||||
goto out2;
|
||||
|
||||
if((mask & KADM5_POLICY)) {
|
||||
HDB_extension ext;
|
||||
|
||||
ext.data.element = choice_HDB_extension_data_policy;
|
||||
ext.data.u.policy = strdup(princ->policy);
|
||||
if (ext.data.u.policy == NULL) {
|
||||
ret = ENOMEM;
|
||||
goto out2;
|
||||
}
|
||||
/* This calls free_HDB_extension(), freeing ext.data.u.policy */
|
||||
ret = hdb_replace_extension(context->context, &ent.entry, &ext);
|
||||
if (ret)
|
||||
goto out2;
|
||||
}
|
||||
|
||||
ret = context->db->hdb_store(context->context, context->db,
|
||||
HDB_F_REPLACE, &ent);
|
||||
if (ret)
|
||||
@@ -80,7 +99,8 @@ modify_principal(void *server_handle,
|
||||
out2:
|
||||
hdb_free_entry(context->context, &ent);
|
||||
out:
|
||||
context->db->hdb_close(context->context, context->db);
|
||||
if (!context->keep_open)
|
||||
context->db->hdb_close(context->context, context->db);
|
||||
return _kadm5_error_code(ret);
|
||||
}
|
||||
|
||||
|
@@ -37,7 +37,7 @@
|
||||
#define __kadm5_privatex_h__
|
||||
|
||||
struct kadm_func {
|
||||
kadm5_ret_t (*chpass_principal) (void *, krb5_principal, const char*);
|
||||
kadm5_ret_t (*chpass_principal) (void *, krb5_principal, int, const char*);
|
||||
kadm5_ret_t (*create_principal) (void*, kadm5_principal_ent_t,
|
||||
uint32_t, const char*);
|
||||
kadm5_ret_t (*delete_principal) (void*, krb5_principal);
|
||||
@@ -48,11 +48,14 @@ struct kadm_func {
|
||||
kadm5_ret_t (*get_principals) (void*, const char*, char***, int*);
|
||||
kadm5_ret_t (*get_privs) (void*, uint32_t*);
|
||||
kadm5_ret_t (*modify_principal) (void*, kadm5_principal_ent_t, uint32_t);
|
||||
kadm5_ret_t (*randkey_principal) (void*, krb5_principal,
|
||||
krb5_keyblock**, int*);
|
||||
kadm5_ret_t (*randkey_principal) (void*, krb5_principal, krb5_boolean, int,
|
||||
krb5_key_salt_tuple*, krb5_keyblock**,
|
||||
int*);
|
||||
kadm5_ret_t (*rename_principal) (void*, krb5_principal, krb5_principal);
|
||||
kadm5_ret_t (*chpass_principal_with_key) (void *, krb5_principal,
|
||||
kadm5_ret_t (*chpass_principal_with_key) (void *, krb5_principal, int,
|
||||
int, krb5_key_data *);
|
||||
kadm5_ret_t (*lock) (void *);
|
||||
kadm5_ret_t (*unlock) (void *);
|
||||
};
|
||||
|
||||
/* XXX should be integrated */
|
||||
@@ -89,6 +92,7 @@ typedef struct kadm5_server_context {
|
||||
/* */
|
||||
kadm5_config_params config;
|
||||
HDB *db;
|
||||
int keep_open;
|
||||
krb5_principal caller;
|
||||
unsigned acl_flags;
|
||||
kadm5_log_context log_context;
|
||||
|
@@ -38,14 +38,18 @@ RCSID("$Id$");
|
||||
kadm5_ret_t
|
||||
kadm5_c_randkey_principal(void *server_handle,
|
||||
krb5_principal princ,
|
||||
krb5_boolean keepold,
|
||||
int n_ks_tuple,
|
||||
krb5_key_salt_tuple *ks_tuple,
|
||||
krb5_keyblock **new_keys,
|
||||
int *n_keys)
|
||||
{
|
||||
kadm5_client_context *context = server_handle;
|
||||
kadm5_ret_t ret;
|
||||
krb5_storage *sp;
|
||||
unsigned char buf[1024];
|
||||
unsigned char buf[1536];
|
||||
int32_t tmp;
|
||||
size_t i;
|
||||
krb5_data reply;
|
||||
|
||||
ret = _kadm5_connect(server_handle);
|
||||
@@ -57,8 +61,37 @@ kadm5_c_randkey_principal(void *server_handle,
|
||||
krb5_clear_error_message(context->context);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE WELL: This message is extensible. It currently consists of:
|
||||
*
|
||||
* - opcode (kadm_randkey)
|
||||
* - principal name (princ)
|
||||
*
|
||||
* followed by optional items, each of which must be present if
|
||||
* there are any items following them that are also present:
|
||||
*
|
||||
* - keepold boolean (whether to delete old kvnos)
|
||||
* - number of key/salt type tuples
|
||||
* - array of {enctype, salttype}
|
||||
*
|
||||
* Eventually we may add:
|
||||
*
|
||||
* - opaque string2key parameters (salt, rounds, ...)
|
||||
*/
|
||||
krb5_store_int32(sp, kadm_randkey);
|
||||
krb5_store_principal(sp, princ);
|
||||
|
||||
if (keepold == TRUE || n_ks_tuple > 0)
|
||||
krb5_store_uint32(sp, keepold);
|
||||
if (n_ks_tuple > 0)
|
||||
krb5_store_uint32(sp, n_ks_tuple);
|
||||
for (i = 0; i < n_ks_tuple; i++) {
|
||||
krb5_store_int32(sp, ks_tuple[i].ks_enctype);
|
||||
krb5_store_int32(sp, ks_tuple[i].ks_salttype);
|
||||
}
|
||||
/* Future extensions go here */
|
||||
|
||||
ret = _kadm5_client_send(context, sp);
|
||||
krb5_storage_free(sp);
|
||||
if (ret)
|
||||
@@ -80,6 +113,10 @@ kadm5_c_randkey_principal(void *server_handle,
|
||||
int i;
|
||||
|
||||
krb5_ret_int32(sp, &tmp);
|
||||
if (tmp < 0) {
|
||||
ret = EOVERFLOW;
|
||||
goto out;
|
||||
}
|
||||
k = malloc(tmp * sizeof(*k));
|
||||
if (k == NULL) {
|
||||
ret = ENOMEM;
|
||||
@@ -87,8 +124,10 @@ kadm5_c_randkey_principal(void *server_handle,
|
||||
}
|
||||
for(i = 0; i < tmp; i++)
|
||||
krb5_ret_keyblock(sp, &k[i]);
|
||||
*n_keys = tmp;
|
||||
*new_keys = k;
|
||||
if (n_keys && new_keys) {
|
||||
*n_keys = tmp;
|
||||
*new_keys = k;
|
||||
}
|
||||
}
|
||||
out:
|
||||
krb5_storage_free(sp);
|
||||
|
@@ -43,6 +43,9 @@ RCSID("$Id$");
|
||||
kadm5_ret_t
|
||||
kadm5_s_randkey_principal(void *server_handle,
|
||||
krb5_principal princ,
|
||||
krb5_boolean keepold,
|
||||
int n_ks_tuple,
|
||||
krb5_key_salt_tuple *ks_tuple,
|
||||
krb5_keyblock **new_keys,
|
||||
int *n_keys)
|
||||
{
|
||||
@@ -51,16 +54,26 @@ kadm5_s_randkey_principal(void *server_handle,
|
||||
kadm5_ret_t ret;
|
||||
|
||||
memset(&ent, 0, sizeof(ent));
|
||||
ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
|
||||
if(ret)
|
||||
return ret;
|
||||
if (!context->keep_open) {
|
||||
ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
|
||||
if(ret)
|
||||
return ret;
|
||||
}
|
||||
ret = context->db->hdb_fetch_kvno(context->context, context->db, princ,
|
||||
HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
|
||||
if(ret)
|
||||
goto out;
|
||||
|
||||
if (keepold) {
|
||||
ret = hdb_add_current_keys_to_history(context->context, &ent.entry);
|
||||
if (ret)
|
||||
goto out2;
|
||||
}
|
||||
|
||||
ret = _kadm5_set_keys_randomly (context,
|
||||
&ent.entry,
|
||||
n_ks_tuple,
|
||||
ks_tuple,
|
||||
new_keys,
|
||||
n_keys);
|
||||
if (ret)
|
||||
@@ -74,9 +87,18 @@ kadm5_s_randkey_principal(void *server_handle,
|
||||
if (ret)
|
||||
goto out2;
|
||||
|
||||
ret = hdb_seal_keys(context->context, context->db, &ent.entry);
|
||||
if (ret)
|
||||
goto out2;
|
||||
if (keepold) {
|
||||
ret = hdb_seal_keys(context->context, context->db, &ent.entry);
|
||||
if (ret)
|
||||
goto out2;
|
||||
} else {
|
||||
HDB_extension ext;
|
||||
|
||||
ext.data.element = choice_HDB_extension_data_hist_keys;
|
||||
ext.data.u.hist_keys.len = 0;
|
||||
ext.data.u.hist_keys.val = NULL;
|
||||
hdb_replace_extension(context->context, &ent.entry, &ext);
|
||||
}
|
||||
|
||||
ret = context->db->hdb_store(context->context, context->db,
|
||||
HDB_F_REPLACE, &ent);
|
||||
@@ -102,6 +124,7 @@ out3:
|
||||
out2:
|
||||
hdb_free_entry(context->context, &ent);
|
||||
out:
|
||||
context->db->hdb_close(context->context, context->db);
|
||||
if (!context->keep_open)
|
||||
context->db->hdb_close(context->context, context->db);
|
||||
return _kadm5_error_code(ret);
|
||||
}
|
||||
|
@@ -48,13 +48,16 @@ kadm5_s_rename_principal(void *server_handle,
|
||||
memset(&ent, 0, sizeof(ent));
|
||||
if(krb5_principal_compare(context->context, source, target))
|
||||
return KADM5_DUP; /* XXX is this right? */
|
||||
ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
|
||||
if(ret)
|
||||
return ret;
|
||||
if (!context->keep_open) {
|
||||
ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
|
||||
if(ret)
|
||||
return ret;
|
||||
}
|
||||
ret = context->db->hdb_fetch_kvno(context->context, context->db,
|
||||
source, HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
|
||||
if(ret){
|
||||
context->db->hdb_close(context->context, context->db);
|
||||
if (!context->keep_open)
|
||||
context->db->hdb_close(context->context, context->db);
|
||||
goto out;
|
||||
}
|
||||
ret = _kadm5_set_modifier(context, &ent.entry);
|
||||
@@ -103,7 +106,8 @@ kadm5_s_rename_principal(void *server_handle,
|
||||
ret = context->db->hdb_remove(context->context, context->db, oldname);
|
||||
ent.entry.principal = oldname;
|
||||
out2:
|
||||
context->db->hdb_close(context->context, context->db);
|
||||
if (!context->keep_open)
|
||||
context->db->hdb_close(context->context, context->db);
|
||||
hdb_free_entry(context->context, &ent);
|
||||
out:
|
||||
return _kadm5_error_code(ret);
|
||||
|
@@ -72,6 +72,23 @@ _kadm5_set_keys(kadm5_server_context *context,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
setup_Key(Key *k, Salt *s, krb5_key_data *kd, size_t kd_offset)
|
||||
{
|
||||
memset(k, 0, sizeof (*k)); /* sets mkvno and salt */
|
||||
k->key.keytype = kd[kd_offset].key_data_type[0];
|
||||
k->key.keyvalue.length = kd[kd_offset].key_data_length[0];
|
||||
k->key.keyvalue.data = kd[kd_offset].key_data_contents[0];
|
||||
|
||||
if(kd[kd_offset].key_data_ver == 2) {
|
||||
memset(s, 0, sizeof (*s));
|
||||
s->type = kd[kd_offset].key_data_type[1];
|
||||
s->salt.length = kd[kd_offset].key_data_length[1];
|
||||
s->salt.data = kd[kd_offset].key_data_contents[1];
|
||||
k->salt = s;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the keys of `ent' to (`n_key_data', `key_data')
|
||||
*/
|
||||
@@ -83,51 +100,161 @@ _kadm5_set_keys2(kadm5_server_context *context,
|
||||
krb5_key_data *key_data)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
int i;
|
||||
unsigned len;
|
||||
Key *keys;
|
||||
size_t i, k;
|
||||
HDB_extension ext;
|
||||
HDB_extension *extp = NULL;
|
||||
HDB_Ext_KeySet *hist_keys = &ext.data.u.hist_keys;
|
||||
Key key;
|
||||
Salt salt;
|
||||
Keys keys;
|
||||
hdb_keyset hkset;
|
||||
krb5_kvno kvno = -1;
|
||||
int one_key_set = 1;
|
||||
int replace_hist_keys = 0;
|
||||
|
||||
len = n_key_data;
|
||||
keys = malloc (len * sizeof(*keys));
|
||||
if (keys == NULL && len != 0)
|
||||
return ENOMEM;
|
||||
|
||||
_kadm5_init_keys (keys, len);
|
||||
|
||||
for(i = 0; i < n_key_data; i++) {
|
||||
keys[i].mkvno = NULL;
|
||||
keys[i].key.keytype = key_data[i].key_data_type[0];
|
||||
ret = krb5_data_copy(&keys[i].key.keyvalue,
|
||||
key_data[i].key_data_contents[0],
|
||||
key_data[i].key_data_length[0]);
|
||||
if(ret)
|
||||
goto out;
|
||||
if(key_data[i].key_data_ver == 2) {
|
||||
Salt *salt;
|
||||
|
||||
salt = calloc(1, sizeof(*salt));
|
||||
if(salt == NULL) {
|
||||
ret = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
keys[i].salt = salt;
|
||||
salt->type = key_data[i].key_data_type[1];
|
||||
krb5_data_copy(&salt->salt,
|
||||
key_data[i].key_data_contents[1],
|
||||
key_data[i].key_data_length[1]);
|
||||
} else
|
||||
keys[i].salt = NULL;
|
||||
if (n_key_data == 0) {
|
||||
/* Clear all keys! */
|
||||
ret = hdb_clear_extension(context->context, ent,
|
||||
choice_HDB_extension_data_hist_keys);
|
||||
if (ret)
|
||||
return ret;
|
||||
free_Keys(&ent->keys);
|
||||
return 0;
|
||||
}
|
||||
_kadm5_free_keys (context->context, ent->keys.len, ent->keys.val);
|
||||
ent->keys.len = len;
|
||||
ent->keys.val = keys;
|
||||
|
||||
memset(&keys, 0, sizeof (keys));
|
||||
memset(&hkset, 0, sizeof (hkset)); /* set set_time */
|
||||
ext.data.element = choice_HDB_extension_data_hist_keys;
|
||||
memset(hist_keys, 0, sizeof (*hist_keys));
|
||||
|
||||
for (i = 0; i < n_key_data; i++) {
|
||||
if (kvno != -1 && kvno != key_data[i].key_data_kvno) {
|
||||
one_key_set = 0;
|
||||
break;
|
||||
}
|
||||
kvno = key_data[i].key_data_kvno;
|
||||
}
|
||||
if (one_key_set) {
|
||||
/*
|
||||
* If we're updating KADM5_KEY_DATA with a single keyset then we
|
||||
* assume we must be setting the principal's kvno as well!
|
||||
*
|
||||
* Just have to be careful about old clients that might have
|
||||
* sent 0 as the kvno... This may seem ugly, but it's the price
|
||||
* of backwards compatibility with pre-multi-kvno kadmin clients
|
||||
* (besides, who's to say that updating KADM5_KEY_DATA requires
|
||||
* updating the entry's kvno?)
|
||||
*
|
||||
* Note that we do nothing special for the case where multiple
|
||||
* keysets are given but the entry's kvno is not set and not in
|
||||
* the given set of keysets. If this happens we'll just update
|
||||
* the key history only and leave the current keyset alone.
|
||||
*/
|
||||
if (kvno == 0) {
|
||||
/* Force kvno to 1 if it was 0; (ank would do this anyways) */
|
||||
if (ent->kvno == 0)
|
||||
ent->kvno = 1;
|
||||
/* Below we need key_data[*].kvno to be reasonable */
|
||||
for (i = 0; i < n_key_data; i++)
|
||||
key_data[i].key_data_kvno = ent->kvno;
|
||||
} else {
|
||||
/*
|
||||
* Or force the entry's kvno to match the one from the new,
|
||||
* singular keyset
|
||||
*/
|
||||
ent->kvno = kvno;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < n_key_data; i++) {
|
||||
if (key_data[i].key_data_kvno == ent->kvno) {
|
||||
/* A current key; add to current key set */
|
||||
setup_Key(&key, &salt, key_data, i);
|
||||
ret = add_Keys(&keys, &key);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* This kvno is historical. Build an hdb_keyset for keys of
|
||||
* this enctype and add them to the new key history.
|
||||
*/
|
||||
for (k = 0; k < hist_keys->len; k++) {
|
||||
if (hist_keys->val[k].kvno == key_data[i].key_data_kvno)
|
||||
break;
|
||||
}
|
||||
if (hist_keys->len > k &&
|
||||
hist_keys->val[k].kvno == key_data[i].key_data_kvno)
|
||||
/* We've added all keys of this kvno already (see below) */
|
||||
continue;
|
||||
|
||||
memset(&hkset, 0, sizeof (hkset)); /* set set_time */
|
||||
hkset.kvno = key_data[i].key_data_kvno;
|
||||
for (k = 0; k < n_key_data; k++) {
|
||||
/* Find all keys of this kvno and add them to the new keyset */
|
||||
if (key_data[k].key_data_kvno != hkset.kvno)
|
||||
continue;
|
||||
|
||||
setup_Key(&key, &salt, key_data, k);
|
||||
ret = add_Keys(&hkset.keys, &key);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
ret = add_HDB_Ext_KeySet(hist_keys, &hkset);
|
||||
if (ret)
|
||||
goto out;
|
||||
replace_hist_keys = 1;
|
||||
}
|
||||
|
||||
if (replace_hist_keys)
|
||||
/* No key history given -> leave it alone */
|
||||
extp = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys);
|
||||
if (extp != NULL) {
|
||||
HDB_Ext_KeySet *old_hist_keys;
|
||||
|
||||
/*
|
||||
* Try to keep the very useful set_time values from the old hist
|
||||
* keys. kadm5 loses this info, so this heuristic is the best we
|
||||
* can do.
|
||||
*/
|
||||
old_hist_keys = &extp->data.u.hist_keys;
|
||||
for (i = 0; i < old_hist_keys->len; i++) {
|
||||
if (old_hist_keys->val[i].set_time == NULL)
|
||||
continue;
|
||||
for (k = 0; k < hist_keys->len; k++) {
|
||||
if (hist_keys->val[k].kvno != old_hist_keys->val[k].kvno)
|
||||
continue;
|
||||
hist_keys->val[k].set_time = old_hist_keys->val[k].set_time;
|
||||
old_hist_keys->val[k].set_time = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (replace_hist_keys) {
|
||||
/* If hist keys not given in key_data then don't blow away hist_keys */
|
||||
ret = hdb_replace_extension(context->context, ent, &ext);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* A structure copy is more efficient here than this would be:
|
||||
*
|
||||
* copy_Keys(&keys, &ent->keys);
|
||||
* free_Keys(&keys);
|
||||
*
|
||||
* Of course, the above hdb_replace_extension() is not at all efficient...
|
||||
*/
|
||||
free_Keys(&ent->keys);
|
||||
ent->keys = keys;
|
||||
hdb_entry_set_pw_change_time(context->context, ent, 0);
|
||||
hdb_entry_clear_password(context->context, ent);
|
||||
|
||||
return 0;
|
||||
out:
|
||||
_kadm5_free_keys (context->context, len, keys);
|
||||
|
||||
out:
|
||||
free_Keys(&keys);
|
||||
free_hdb_keyset(&hkset);
|
||||
free_HDB_extension(&ext);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -196,6 +323,8 @@ is_des_key_p(int keytype)
|
||||
kadm5_ret_t
|
||||
_kadm5_set_keys_randomly (kadm5_server_context *context,
|
||||
hdb_entry *ent,
|
||||
int n_ks_tuple,
|
||||
krb5_key_salt_tuple *ks_tuple,
|
||||
krb5_keyblock **new_keys,
|
||||
int *n_keys)
|
||||
{
|
||||
@@ -206,7 +335,7 @@ _kadm5_set_keys_randomly (kadm5_server_context *context,
|
||||
Key *keys;
|
||||
|
||||
ret = hdb_generate_key_set(context->context, ent->principal,
|
||||
&keys, &num_keys, 1);
|
||||
n_ks_tuple, ks_tuple, &keys, &num_keys, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -263,8 +392,10 @@ out:
|
||||
_kadm5_free_keys (context->context, ent->keys.len, ent->keys.val);
|
||||
ent->keys.val = keys;
|
||||
ent->keys.len = num_keys;
|
||||
*new_keys = kblock;
|
||||
*n_keys = num_keys;
|
||||
if (n_keys && new_keys) {
|
||||
*new_keys = kblock;
|
||||
*n_keys = num_keys;
|
||||
}
|
||||
|
||||
hdb_entry_set_pw_change_time(context->context, ent, 0);
|
||||
hdb_entry_clear_password(context->context, ent);
|
||||
|
@@ -7,14 +7,22 @@ HEIMDAL_KAMD5_SERVER_1.0 {
|
||||
kadm5_add_passwd_quality_verifier;
|
||||
kadm5_check_password_quality;
|
||||
kadm5_chpass_principal;
|
||||
kadm5_chpass_principal_3;
|
||||
kadm5_chpass_principal_with_key;
|
||||
kadm5_chpass_principal_with_key_3;
|
||||
kadm5_create_policy;
|
||||
kadm5_create_principal;
|
||||
kadm5_delete_principal;
|
||||
kadm5_destroy;
|
||||
kadm5_decrypt_key;
|
||||
kadm5_delete_policy;
|
||||
kadm5_flush;
|
||||
kadm5_free_key_data;
|
||||
kadm5_free_name_list;
|
||||
kadm5_free_policy_ent;
|
||||
kadm5_free_principal_ent;
|
||||
kadm5_get_policy;
|
||||
kadm5_get_policies;
|
||||
kadm5_get_principal;
|
||||
kadm5_get_principals;
|
||||
kadm5_get_privs;
|
||||
@@ -24,18 +32,25 @@ HEIMDAL_KAMD5_SERVER_1.0 {
|
||||
kadm5_init_with_password_ctx;
|
||||
kadm5_init_with_skey;
|
||||
kadm5_init_with_skey_ctx;
|
||||
kadm5_lock;
|
||||
kadm5_modify_principal;
|
||||
kadm5_modify_policy;
|
||||
kadm5_randkey_principal;
|
||||
kadm5_randkey_principal_3;
|
||||
kadm5_rename_principal;
|
||||
kadm5_ret_key_data;
|
||||
kadm5_ret_principal_ent;
|
||||
kadm5_ret_principal_ent_mask;
|
||||
kadm5_ret_tl_data;
|
||||
kadm5_setup_passwd_quality_check;
|
||||
kadm5_setkey_principal;
|
||||
kadm5_setkey_principal_3;
|
||||
kadm5_store_key_data;
|
||||
kadm5_store_principal_ent;
|
||||
kadm5_store_principal_ent_mask;
|
||||
kadm5_store_principal_ent_nokeys;
|
||||
kadm5_store_tl_data;
|
||||
kadm5_unlock;
|
||||
kadm5_s_init_with_password_ctx;
|
||||
kadm5_s_init_with_password;
|
||||
kadm5_s_init_with_skey_ctx;
|
||||
|
Reference in New Issue
Block a user