Fixes for updates of KADM5_KVNO but not KEY_DATA and vice-versa.
It turns out that updates of kvno but not key data and vice-versa are both, allowed and actually done (e.g, in kadmin's ank). Doing the right thing in these cases turns out to be a bit tricky, but this commit ought to do it.
This commit is contained in:
@@ -160,6 +160,12 @@ add_one_principal (const char *name,
|
|||||||
kadm5_get_principal(kadm_handle, princ_ent, &princ,
|
kadm5_get_principal(kadm_handle, princ_ent, &princ,
|
||||||
KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES);
|
KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES);
|
||||||
princ.attributes &= (~KRB5_KDB_DISALLOW_ALL_TIX);
|
princ.attributes &= (~KRB5_KDB_DISALLOW_ALL_TIX);
|
||||||
|
/*
|
||||||
|
* Updating kvno w/o key data and vice-versa gives _kadm5_setup_entry()
|
||||||
|
* and _kadm5_set_keys2() headaches. But we used to, so we handle
|
||||||
|
* this in in those two functions. Might as well leave this code as
|
||||||
|
* it was then.
|
||||||
|
*/
|
||||||
princ.kvno = 1;
|
princ.kvno = 1;
|
||||||
kadm5_modify_principal(kadm_handle, &princ,
|
kadm5_modify_principal(kadm_handle, &princ,
|
||||||
KADM5_ATTRIBUTES | KADM5_KVNO);
|
KADM5_ATTRIBUTES | KADM5_KVNO);
|
||||||
|
@@ -106,6 +106,10 @@ del_enctype(void *opt, int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
free (princ.key_data);
|
free (princ.key_data);
|
||||||
|
if (j == 0) {
|
||||||
|
free(new_key_data);
|
||||||
|
new_key_data = NULL;
|
||||||
|
}
|
||||||
princ.n_key_data = j;
|
princ.n_key_data = j;
|
||||||
princ.key_data = new_key_data;
|
princ.key_data = new_key_data;
|
||||||
|
|
||||||
|
@@ -60,7 +60,7 @@ static struct field_name {
|
|||||||
{ "last_failed", KADM5_LAST_FAILED, 0, 0, "Last fail", "Last failed login", 0 },
|
{ "last_failed", KADM5_LAST_FAILED, 0, 0, "Last fail", "Last failed login", 0 },
|
||||||
{ "fail_auth_count", KADM5_FAIL_AUTH_COUNT, 0, 0, "Fail count", "Failed login count", RTBL_ALIGN_RIGHT },
|
{ "fail_auth_count", KADM5_FAIL_AUTH_COUNT, 0, 0, "Fail count", "Failed login count", RTBL_ALIGN_RIGHT },
|
||||||
{ "policy", KADM5_POLICY, 0, 0, "Policy", "Policy", 0 },
|
{ "policy", KADM5_POLICY, 0, 0, "Policy", "Policy", 0 },
|
||||||
{ "keytypes", KADM5_KEY_DATA, 0, KADM5_PRINCIPAL, "Keytypes", "Keytypes", 0 },
|
{ "keytypes", KADM5_KEY_DATA, 0, KADM5_PRINCIPAL | KADM5_KVNO, "Keytypes", "Keytypes", 0 },
|
||||||
{ "password", KADM5_TL_DATA, KRB5_TL_PASSWORD, KADM5_KEY_DATA, "Password", "Password", 0 },
|
{ "password", KADM5_TL_DATA, KRB5_TL_PASSWORD, KADM5_KEY_DATA, "Password", "Password", 0 },
|
||||||
{ "pkinit-acl", KADM5_TL_DATA, KRB5_TL_PKINIT_ACL, 0, "PK-INIT ACL", "PK-INIT ACL", 0 },
|
{ "pkinit-acl", KADM5_TL_DATA, KRB5_TL_PKINIT_ACL, 0, "PK-INIT ACL", "PK-INIT ACL", 0 },
|
||||||
{ "aliases", KADM5_TL_DATA, KRB5_TL_ALIASES, 0, "Aliases", "Aliases", 0 },
|
{ "aliases", KADM5_TL_DATA, KRB5_TL_ALIASES, 0, "Aliases", "Aliases", 0 },
|
||||||
|
@@ -258,7 +258,7 @@ kadm5_setkey_principal_3(void *server_handle,
|
|||||||
return KADM5_SETKEY3_ETYPE_MISMATCH;
|
return KADM5_SETKEY3_ETYPE_MISMATCH;
|
||||||
|
|
||||||
ret = kadm5_get_principal(server_handle, princ, &princ_ent,
|
ret = kadm5_get_principal(server_handle, princ, &princ_ent,
|
||||||
KADM5_PRINCIPAL | KADM5_KEY_DATA);
|
KADM5_KVNO | KADM5_PRINCIPAL | KADM5_KEY_DATA);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@@ -111,6 +111,12 @@ kadm5_s_create_principal_with_key(void *server_handle,
|
|||||||
hdb_entry_ex ent;
|
hdb_entry_ex ent;
|
||||||
kadm5_server_context *context = server_handle;
|
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,
|
ret = create_principal(context, princ, mask, &ent,
|
||||||
KADM5_PRINCIPAL | KADM5_KEY_DATA,
|
KADM5_PRINCIPAL | KADM5_KEY_DATA,
|
||||||
KADM5_LAST_PWD_CHANGE | KADM5_MOD_TIME
|
KADM5_LAST_PWD_CHANGE | KADM5_MOD_TIME
|
||||||
@@ -121,9 +127,6 @@ kadm5_s_create_principal_with_key(void *server_handle,
|
|||||||
if(ret)
|
if(ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if ((mask & KADM5_KVNO) == 0)
|
|
||||||
ent.entry.kvno = 1;
|
|
||||||
|
|
||||||
ret = hdb_seal_keys(context->context, context->db, &ent.entry);
|
ret = hdb_seal_keys(context->context, context->db, &ent.entry);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
@@ -153,6 +156,12 @@ kadm5_s_create_principal(void *server_handle,
|
|||||||
hdb_entry_ex ent;
|
hdb_entry_ex ent;
|
||||||
kadm5_server_context *context = server_handle;
|
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,
|
ret = create_principal(context, princ, mask, &ent,
|
||||||
KADM5_PRINCIPAL,
|
KADM5_PRINCIPAL,
|
||||||
KADM5_LAST_PWD_CHANGE | KADM5_MOD_TIME
|
KADM5_LAST_PWD_CHANGE | KADM5_MOD_TIME
|
||||||
@@ -163,9 +172,6 @@ kadm5_s_create_principal(void *server_handle,
|
|||||||
if(ret)
|
if(ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if ((mask & KADM5_KVNO) == 0)
|
|
||||||
ent.entry.kvno = 1;
|
|
||||||
|
|
||||||
ent.entry.keys.len = 0;
|
ent.entry.keys.len = 0;
|
||||||
ent.entry.keys.val = NULL;
|
ent.entry.keys.val = NULL;
|
||||||
|
|
||||||
|
@@ -178,8 +178,27 @@ _kadm5_setup_entry(kadm5_server_context *context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(mask & KADM5_KVNO
|
if(mask & KADM5_KVNO
|
||||||
&& princ_mask & KADM5_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;
|
ent->entry.kvno = princ->kvno;
|
||||||
|
}
|
||||||
|
}
|
||||||
if(mask & KADM5_MAX_RLIFE) {
|
if(mask & KADM5_MAX_RLIFE) {
|
||||||
if(princ_mask & KADM5_MAX_RLIFE) {
|
if(princ_mask & KADM5_MAX_RLIFE) {
|
||||||
if(princ->max_renewable_life)
|
if(princ->max_renewable_life)
|
||||||
|
@@ -102,18 +102,70 @@ _kadm5_set_keys2(kadm5_server_context *context,
|
|||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
size_t i, k;
|
size_t i, k;
|
||||||
HDB_extension ext;
|
HDB_extension ext;
|
||||||
HDB_extension *extp;
|
HDB_extension *extp = NULL;
|
||||||
HDB_Ext_KeySet *hist_keys = &ext.data.u.hist_keys;
|
HDB_Ext_KeySet *hist_keys = &ext.data.u.hist_keys;
|
||||||
Key key;
|
Key key;
|
||||||
Salt salt;
|
Salt salt;
|
||||||
Keys keys;
|
Keys keys;
|
||||||
hdb_keyset hkset;
|
hdb_keyset hkset;
|
||||||
|
krb5_kvno kvno = -1;
|
||||||
|
int one_key_set = 1;
|
||||||
|
int replace_hist_keys = 0;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
memset(&keys, 0, sizeof (keys));
|
memset(&keys, 0, sizeof (keys));
|
||||||
memset(&hkset, 0, sizeof (hkset)); /* set set_time */
|
memset(&hkset, 0, sizeof (hkset)); /* set set_time */
|
||||||
ext.data.element = choice_HDB_extension_data_hist_keys;
|
ext.data.element = choice_HDB_extension_data_hist_keys;
|
||||||
memset(hist_keys, 0, sizeof (*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++) {
|
for (i = 0; i < n_key_data; i++) {
|
||||||
if (key_data[i].key_data_kvno == ent->kvno) {
|
if (key_data[i].key_data_kvno == ent->kvno) {
|
||||||
/* A current key; add to current key set */
|
/* A current key; add to current key set */
|
||||||
@@ -150,22 +202,20 @@ _kadm5_set_keys2(kadm5_server_context *context,
|
|||||||
ret = add_HDB_Ext_KeySet(hist_keys, &hkset);
|
ret = add_HDB_Ext_KeySet(hist_keys, &hkset);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
replace_hist_keys = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (replace_hist_keys)
|
||||||
* A structure copy is more efficient here than this would be:
|
/* No key history given -> leave it alone */
|
||||||
*
|
|
||||||
* copy_Keys(&keys, &ent->keys);
|
|
||||||
* free_Keys(&keys);
|
|
||||||
*/
|
|
||||||
free_Keys(&ent->keys);
|
|
||||||
ent->keys = keys;
|
|
||||||
|
|
||||||
/* Try to keep the set_time values from the old hist keys */
|
|
||||||
extp = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys);
|
extp = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys);
|
||||||
if (extp != NULL) {
|
if (extp != NULL) {
|
||||||
HDB_Ext_KeySet *old_hist_keys;
|
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;
|
old_hist_keys = &extp->data.u.hist_keys;
|
||||||
for (i = 0; i < old_hist_keys->len; i++) {
|
for (i = 0; i < old_hist_keys->len; i++) {
|
||||||
if (old_hist_keys->val[i].set_time == NULL)
|
if (old_hist_keys->val[i].set_time == NULL)
|
||||||
@@ -179,7 +229,23 @@ _kadm5_set_keys2(kadm5_server_context *context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hdb_replace_extension(context->context, ent, &ext);
|
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_set_pw_change_time(context->context, ent, 0);
|
||||||
hdb_entry_clear_password(context->context, ent);
|
hdb_entry_clear_password(context->context, ent);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user