diff options
| author | Nicolas Williams <nico@cryptonector.com> | 2012-07-18 16:27:35 -0500 |
|---|---|---|
| committer | Greg Hudson <ghudson@mit.edu> | 2012-07-30 19:11:28 -0400 |
| commit | 5829ca2b348974e52a67b553afc7f7491007c33a (patch) | |
| tree | 3fdbcdfc56a26445c2f2fce9fb72b6deddb28d0f /src/lib/kadm5/srv | |
| parent | 796366a03ea170efb937913acae36a2083a5329e (diff) | |
| download | krb5-5829ca2b348974e52a67b553afc7f7491007c33a.tar.gz krb5-5829ca2b348974e52a67b553afc7f7491007c33a.tar.xz krb5-5829ca2b348974e52a67b553afc7f7491007c33a.zip | |
Policy extensions + new policy: allowed ks types
This simply adds KADM5_API_VERSION_4 and various fields to the
policy structures:
- attributes (policy-ish principal attributes)
- max_life (max ticket life)
- max_renewable_life (max ticket renewable life)
- allowed_keysalts (allowed key/salt types)
- TL data (future policy extensions)
Of these only allowed_keysalts is currently implemented.
Some refactoring of TL data handling is also done.
ticket: 7223 (new)
Diffstat (limited to 'src/lib/kadm5/srv')
| -rw-r--r-- | src/lib/kadm5/srv/server_init.c | 2 | ||||
| -rw-r--r-- | src/lib/kadm5/srv/svr_policy.c | 190 | ||||
| -rw-r--r-- | src/lib/kadm5/srv/svr_principal.c | 258 |
3 files changed, 398 insertions, 52 deletions
diff --git a/src/lib/kadm5/srv/server_init.c b/src/lib/kadm5/srv/server_init.c index b170e9e7c5..3c3a8795fb 100644 --- a/src/lib/kadm5/srv/server_init.c +++ b/src/lib/kadm5/srv/server_init.c @@ -283,7 +283,7 @@ kadm5_ret_t kadm5_init(krb5_context context, char *client_name, char *pass, return ENOMEM; } *handle->lhandle = *handle; - handle->lhandle->api_version = KADM5_API_VERSION_3; + handle->lhandle->api_version = KADM5_API_VERSION_4; handle->lhandle->struct_version = KADM5_STRUCT_VERSION; handle->lhandle->lhandle = handle->lhandle; diff --git a/src/lib/kadm5/srv/svr_policy.c b/src/lib/kadm5/srv/svr_policy.c index 4e0065c3d3..3a8f82ecf2 100644 --- a/src/lib/kadm5/srv/svr_policy.c +++ b/src/lib/kadm5/srv/svr_policy.c @@ -52,6 +52,24 @@ kadm5_create_policy(void *server_handle, return kadm5_create_policy_internal(server_handle, entry, mask); } +/* Validate allowed_keysalts. */ +static kadm5_ret_t +validate_allowed_keysalts(char *allowed_keysalts) +{ + kadm5_ret_t ret; + krb5_key_salt_tuple *ks_tuple = NULL; + krb5_int32 n_ks_tuple = 0; + + if (strchr(allowed_keysalts, '\t') != NULL) + return KADM5_BAD_KEYSALTS; + ret = krb5_string_to_keysalts(allowed_keysalts, ",", ":.-", 0, + &ks_tuple, &n_ks_tuple); + free(ks_tuple); + if (ret == EINVAL) + return KADM5_BAD_KEYSALTS; + return ret; +} + /* * Function: kadm5_create_policy_internal * @@ -89,7 +107,14 @@ kadm5_create_policy_internal(void *server_handle, return KADM5_BAD_POLICY; if (!(mask & KADM5_POLICY)) return KADM5_BAD_MASK; + if ((mask & KADM5_POLICY_ALLOWED_KEYSALTS) && + entry->allowed_keysalts != NULL) { + ret = validate_allowed_keysalts(entry->allowed_keysalts); + if (ret) + return ret; + } + memset(&pent, 0, sizeof(pent)); pent.name = entry->policy; p = entry->policy; while(*p != '\0') { @@ -138,7 +163,32 @@ kadm5_create_policy_internal(void *server_handle, else pent.policy_refcnt = entry->policy_refcnt; - if (handle->api_version == KADM5_API_VERSION_3) { + if (handle->api_version >= KADM5_API_VERSION_4) { + if (!(mask & KADM5_POLICY_ATTRIBUTES)) + pent.attributes = 0; + else + pent.attributes = entry->attributes; + if (!(mask & KADM5_POLICY_MAX_LIFE)) + pent.max_life = 0; + else + pent.max_life = entry->max_life; + if (!(mask & KADM5_POLICY_MAX_RLIFE)) + pent.max_renewable_life = 0; + else + pent.max_renewable_life = entry->max_renewable_life; + if (!(mask & KADM5_POLICY_ALLOWED_KEYSALTS)) + pent.allowed_keysalts = 0; + else + pent.allowed_keysalts = entry->allowed_keysalts; + if (!(mask & KADM5_POLICY_TL_DATA)) { + pent.n_tl_data = 0; + pent.tl_data = NULL; + } else { + pent.n_tl_data = entry->n_tl_data; + pent.tl_data = entry->tl_data; + } + } + if (handle->api_version >= KADM5_API_VERSION_3) { if (!(mask & KADM5_PW_MAX_FAILURE)) pent.pw_max_fail = 0; else @@ -151,10 +201,6 @@ kadm5_create_policy_internal(void *server_handle, pent.pw_lockout_duration = 0; else pent.pw_lockout_duration = entry->pw_lockout_duration; - } else { - pent.pw_max_fail = 0; - pent.pw_failcnt_interval = 0; - pent.pw_lockout_duration = 0; } if ((ret = krb5_db_create_policy(handle->context, &pent))) @@ -209,13 +255,58 @@ kadm5_modify_policy(void *server_handle, return kadm5_modify_policy_internal(server_handle, entry, mask); } +/* Allocate and form a TL data list of a desired size. */ +static int +alloc_tl_data(krb5_int16 n_tl_data, krb5_tl_data **tldp) +{ + krb5_tl_data **tlp = tldp; + int i; + + for (i = 0; i < n_tl_data; i++) { + *tlp = calloc(1, sizeof(krb5_tl_data)); + if (*tlp == NULL) + return ENOMEM; /* caller cleans up */ + memset(*tlp, 0, sizeof(krb5_tl_data)); + tlp = &((*tlp)->tl_data_next); + } + + return 0; +} + +static kadm5_ret_t +copy_tl_data(krb5_int16 n_tl_data, krb5_tl_data *tl_data, + krb5_tl_data **out) +{ + kadm5_ret_t ret; + krb5_tl_data *tl, *tl_new; + + if ((ret = alloc_tl_data(n_tl_data, out))) + return ret; /* caller cleans up */ + + tl = tl_data; + tl_new = *out; + for (; tl; tl = tl->tl_data_next, tl_new = tl_new->tl_data_next) { + tl_new->tl_data_contents = malloc(tl->tl_data_length); + if (tl_new->tl_data_contents == NULL) + return ENOMEM; + memcpy(tl_new->tl_data_contents, tl->tl_data_contents, + tl->tl_data_length); + tl_new->tl_data_type = tl->tl_data_type; + tl_new->tl_data_length = tl->tl_data_length; + } + + return 0; +} + kadm5_ret_t kadm5_modify_policy_internal(void *server_handle, kadm5_policy_ent_t entry, long mask) { - kadm5_server_handle_t handle = server_handle; - osa_policy_ent_t p; - int ret; + kadm5_server_handle_t handle = server_handle; + krb5_tl_data *tl; + osa_policy_ent_t p; + int ret; + size_t len; CHECK_HANDLE(server_handle); @@ -225,6 +316,20 @@ kadm5_modify_policy_internal(void *server_handle, return KADM5_BAD_POLICY; if((mask & KADM5_POLICY)) return KADM5_BAD_MASK; + if ((mask & KADM5_POLICY_ALLOWED_KEYSALTS) && + entry->allowed_keysalts != NULL) { + ret = validate_allowed_keysalts(entry->allowed_keysalts); + if (ret) + return ret; + } + if ((mask & KADM5_POLICY_TL_DATA)) { + tl = entry->tl_data; + while (tl != NULL) { + if (tl->tl_data_type < 256) + return KADM5_BAD_TL_TYPE; + tl = tl->tl_data_next; + } + } ret = krb5_db_get_policy(handle->context, entry->policy, &p); if (ret == KRB5_KDB_NOENTRY) @@ -265,7 +370,7 @@ kadm5_modify_policy_internal(void *server_handle, } if ((mask & KADM5_REF_COUNT)) p->policy_refcnt = entry->policy_refcnt; - if (handle->api_version == KADM5_API_VERSION_3) { + if (handle->api_version >= KADM5_API_VERSION_3) { if ((mask & KADM5_PW_MAX_FAILURE)) p->pw_max_fail = entry->pw_max_fail; if ((mask & KADM5_PW_FAILURE_COUNT_INTERVAL)) @@ -273,7 +378,39 @@ kadm5_modify_policy_internal(void *server_handle, if ((mask & KADM5_PW_LOCKOUT_DURATION)) p->pw_lockout_duration = entry->pw_lockout_duration; } + if (handle->api_version >= KADM5_API_VERSION_4) { + if ((mask & KADM5_POLICY_ATTRIBUTES)) + p->attributes = entry->attributes; + if ((mask & KADM5_POLICY_MAX_LIFE)) + p->max_life = entry->max_life; + if ((mask & KADM5_POLICY_MAX_RLIFE)) + p->max_renewable_life = entry->max_renewable_life; + if ((mask & KADM5_POLICY_ALLOWED_KEYSALTS)) { + krb5_db_free(handle->context, p->allowed_keysalts); + p->allowed_keysalts = NULL; + if (entry->allowed_keysalts != NULL) { + len = strlen(entry->allowed_keysalts) + 1; + p->allowed_keysalts = krb5_db_alloc(handle->context, NULL, + len); + if (p->allowed_keysalts == NULL) { + ret = ENOMEM; + goto cleanup; + } + memcpy(p->allowed_keysalts, entry->allowed_keysalts, len); + } + } + if ((mask & KADM5_POLICY_TL_DATA)) { + for (tl = entry->tl_data; tl != NULL; tl = tl->tl_data_next) { + ret = krb5_db_update_tl_data(handle->context, &p->n_tl_data, + &p->tl_data, tl); + if (ret) + goto cleanup; + } + } + } ret = krb5_db_put_policy(handle->context, p); + +cleanup: krb5_db_free_policy(handle->context, p); return ret; } @@ -283,9 +420,11 @@ kadm5_get_policy(void *server_handle, kadm5_policy_t name, kadm5_policy_ent_t entry) { osa_policy_ent_t t; - int ret; + kadm5_ret_t ret; kadm5_server_handle_t handle = server_handle; + memset(entry, 0, sizeof(*entry)); + CHECK_HANDLE(server_handle); krb5_clear_error_message(handle->context); @@ -301,8 +440,8 @@ kadm5_get_policy(void *server_handle, kadm5_policy_t name, return ret; if ((entry->policy = strdup(t->name)) == NULL) { - krb5_db_free_policy(handle->context, t); - return ENOMEM; + ret = ENOMEM; + goto cleanup; } entry->pw_min_life = t->pw_min_life; entry->pw_max_life = t->pw_max_life; @@ -310,12 +449,33 @@ kadm5_get_policy(void *server_handle, kadm5_policy_t name, entry->pw_min_classes = t->pw_min_classes; entry->pw_history_num = t->pw_history_num; entry->policy_refcnt = t->policy_refcnt; - if (handle->api_version == KADM5_API_VERSION_3) { + if (handle->api_version >= KADM5_API_VERSION_3) { entry->pw_max_fail = t->pw_max_fail; entry->pw_failcnt_interval = t->pw_failcnt_interval; entry->pw_lockout_duration = t->pw_lockout_duration; } - krb5_db_free_policy(handle->context, t); + if (handle->api_version >= KADM5_API_VERSION_4) { + entry->attributes = t->attributes; + entry->max_life = t->max_life; + entry->max_renewable_life = t->max_renewable_life; + if (t->allowed_keysalts) { + entry->allowed_keysalts = strdup(t->allowed_keysalts); + if (!entry->allowed_keysalts) { + ret = ENOMEM; + goto cleanup; + } + } + ret = copy_tl_data(t->n_tl_data, t->tl_data, &entry->tl_data); + if (ret) + goto cleanup; + entry->n_tl_data = t->n_tl_data; + } + + ret = 0; - return KADM5_OK; +cleanup: + if (ret) + kadm5_free_policy_ent(handle, entry); + krb5_db_free_policy(handle->context, t); + return ret; } diff --git a/src/lib/kadm5/srv/svr_principal.c b/src/lib/kadm5/srv/svr_principal.c index f5ea005b27..f405f55ca9 100644 --- a/src/lib/kadm5/srv/svr_principal.c +++ b/src/lib/kadm5/srv/svr_principal.c @@ -173,6 +173,138 @@ static void cleanup_key_data(context, count, data) krb5_db_free(context, data); } +/* Check whether a ks_tuple is present in an array of ks_tuples. */ +static krb5_boolean +ks_tuple_present(int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, + krb5_key_salt_tuple *looking_for) +{ + int i; + + for (i = 0; i < n_ks_tuple; i++) { + if (ks_tuple[i].ks_enctype == looking_for->ks_enctype && + ks_tuple[i].ks_salttype == looking_for->ks_salttype) + return TRUE; + } + return FALSE; +} + +/* + * Apply the -allowedkeysalts policy (see kadmin(1)'s addpol/modpol + * commands). We use the allowed key/salt tuple list as a default if + * no ks tuples as provided by the caller. We reject lists that include + * key/salts outside the policy. We re-order the requested ks tuples + * (which may be a subset of the policy) to reflect the policy order. + */ +static kadm5_ret_t +apply_keysalt_policy(kadm5_server_handle_t handle, const char *policy, + int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, + int *new_n_kstp, krb5_key_salt_tuple **new_kstp) +{ + kadm5_ret_t ret; + kadm5_policy_ent_rec polent; + int ak_n_ks_tuple = 0; + int new_n_ks_tuple = 0; + krb5_key_salt_tuple *ak_ks_tuple = NULL; + krb5_key_salt_tuple *new_ks_tuple = NULL; + krb5_key_salt_tuple *subset; + int i, m; + + if (new_n_kstp != NULL) { + *new_n_kstp = 0; + *new_kstp = NULL; + } + + memset(&polent, 0, sizeof(polent)); + if (policy != NULL && + (ret = kadm5_get_policy(handle->lhandle, (char *)policy, + &polent)) != KADM5_OK) { + if (ret == EINVAL) + ret = KADM5_BAD_POLICY; + if (ret) + goto cleanup; + } + + if (polent.allowed_keysalts == NULL && new_n_kstp != NULL) { + /* Requested keysalts allowed or default to supported_enctypes. */ + if (n_ks_tuple == 0) { + /* Default to supported_enctypes. */ + n_ks_tuple = handle->params.num_keysalts; + ks_tuple = handle->params.keysalts; + } + /* Dup the requested or defaulted keysalt tuples. */ + new_ks_tuple = malloc(n_ks_tuple * sizeof(*new_ks_tuple)); + if (new_ks_tuple == NULL) { + ret = ENOMEM; + goto cleanup; + } + memcpy(new_ks_tuple, ks_tuple, n_ks_tuple * sizeof(*new_ks_tuple)); + new_n_ks_tuple = n_ks_tuple; + ret = 0; + goto cleanup; + } + + ret = krb5_string_to_keysalts(polent.allowed_keysalts, + ", ", /* Tuple separators */ + ":.-", /* Key/salt separators */ + 0, /* No duplicates */ + &ak_ks_tuple, + &ak_n_ks_tuple); + /* + * Malformed policy? Shouldn't happen, but it's remotely possible + * someday, so we don't assert, just bail. + */ + if (ret) + goto cleanup; + + /* Check that the requested ks_tuples are within policy, if we have one. */ + for (i = 0; i < n_ks_tuple; i++) { + if (!ks_tuple_present(ak_n_ks_tuple, ak_ks_tuple, &ks_tuple[i])) { + ret = KADM5_BAD_KEYSALTS; + goto cleanup; + } + } + + /* Have policy but no ks_tuple input? Output the policy. */ + if (n_ks_tuple == 0) { + new_n_ks_tuple = ak_n_ks_tuple; + new_ks_tuple = ak_ks_tuple; + ak_ks_tuple = NULL; + goto cleanup; + } + + /* + * Now filter the policy ks tuples by the requested ones so as to + * preserve in the requested sub-set the relative ordering from the + * policy. We could optimize this (if (n_ks_tuple == ak_n_ks_tuple) + * then skip this), but we don't bother. + */ + subset = calloc(n_ks_tuple, sizeof(*subset)); + if (subset == NULL) { + ret = ENOMEM; + goto cleanup; + } + for (m = 0, i = 0; i < ak_n_ks_tuple && m < n_ks_tuple; i++) { + if (ks_tuple_present(n_ks_tuple, ks_tuple, &ak_ks_tuple[i])) + subset[m++] = ak_ks_tuple[i]; + } + new_ks_tuple = subset; + new_n_ks_tuple = m; + ret = 0; + +cleanup: + kadm5_free_policy_ent(handle->lhandle, &polent); + free(ak_ks_tuple); + + if (new_n_kstp != NULL) { + *new_n_kstp = new_n_ks_tuple; + *new_kstp = new_ks_tuple; + } else { + free(new_ks_tuple); + } + return ret; +} + + /* * Set *passptr to NULL if the request looks like the first part of a krb5 1.6 * addprinc -randkey operation. The krb5 1.6 dummy password for these requests @@ -224,6 +356,8 @@ kadm5_create_principal_3(void *server_handle, kadm5_server_handle_t handle = server_handle; krb5_keyblock *act_mkey; krb5_kvno act_kvno; + int new_n_ks_tuple = 0; + krb5_key_salt_tuple *new_ks_tuple = NULL; CHECK_HANDLE(server_handle); @@ -247,12 +381,6 @@ kadm5_create_principal_3(void *server_handle, if (entry == NULL) return EINVAL; - /* Use default keysalts if caller did not provide any. */ - if (n_ks_tuple == 0) { - ks_tuple = handle->params.keysalts; - n_ks_tuple = handle->params.num_keysalts; - } - /* * Check to see if the principal exists */ @@ -362,6 +490,16 @@ kadm5_create_principal_3(void *server_handle, } } + /* + * We need to have setup the TL data, so we have strings, so we can + * check enctype policy, which is why we check/initialize ks_tuple + * this late. + */ + ret = apply_keysalt_policy(handle, entry->policy, n_ks_tuple, ks_tuple, + &new_n_ks_tuple, &new_ks_tuple); + if (ret) + goto cleanup; + /* initialize the keys */ ret = krb5_dbe_find_act_mkey(handle->context, active_mkey_list, &act_kvno, @@ -370,13 +508,14 @@ kadm5_create_principal_3(void *server_handle, goto cleanup; if (password) { - ret = krb5_dbe_cpw(handle->context, act_mkey, ks_tuple, n_ks_tuple, - password, (mask & KADM5_KVNO)?entry->kvno:1, + ret = krb5_dbe_cpw(handle->context, act_mkey, new_ks_tuple, + new_n_ks_tuple, password, + (mask & KADM5_KVNO)?entry->kvno:1, FALSE, kdb); } else { /* Null password means create with random key (new in 1.8). */ ret = krb5_dbe_crk(handle->context, &master_keyblock, - ks_tuple, n_ks_tuple, FALSE, kdb); + new_ks_tuple, new_n_ks_tuple, FALSE, kdb); } if (ret) goto cleanup; @@ -388,7 +527,7 @@ kadm5_create_principal_3(void *server_handle, ret = k5_kadm5_hook_create(handle->context, handle->hook_handles, KADM5_HOOK_STAGE_PRECOMMIT, entry, mask, - n_ks_tuple, ks_tuple, password); + new_n_ks_tuple, new_ks_tuple, password); if (ret) goto cleanup; @@ -441,9 +580,10 @@ kadm5_create_principal_3(void *server_handle, (void) k5_kadm5_hook_create(handle->context, handle->hook_handles, KADM5_HOOK_STAGE_POSTCOMMIT, entry, mask, - n_ks_tuple, ks_tuple, password); + new_n_ks_tuple, new_ks_tuple, password); cleanup: + free(new_ks_tuple); krb5_db_free_principal(handle->context, kdb); if (have_polent) (void) kadm5_free_policy_ent(handle->lhandle, &polent); @@ -1345,6 +1485,8 @@ kadm5_chpass_principal_3(void *server_handle, osa_pw_hist_ent hist; krb5_keyblock *act_mkey, *hist_keyblocks = NULL; krb5_kvno act_kvno, hist_kvno; + int new_n_ks_tuple = 0; + krb5_key_salt_tuple *new_ks_tuple = NULL; CHECK_HANDLE(server_handle); @@ -1359,15 +1501,14 @@ kadm5_chpass_principal_3(void *server_handle, principal, hist_princ)) == TRUE) return KADM5_PROTECT_PRINCIPAL; - /* Use default keysalts if caller did not provide any. */ - if (n_ks_tuple == 0) { - ks_tuple = handle->params.keysalts; - n_ks_tuple = handle->params.num_keysalts; - } - if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) return(ret); + ret = apply_keysalt_policy(handle, adb.policy, n_ks_tuple, ks_tuple, + &new_n_ks_tuple, &new_ks_tuple); + if (ret) + goto done; + if ((adb.aux_attributes & KADM5_POLICY)) { if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &pol))) goto done; @@ -1392,7 +1533,7 @@ kadm5_chpass_principal_3(void *server_handle, if (ret) goto done; - ret = krb5_dbe_cpw(handle->context, act_mkey, ks_tuple, n_ks_tuple, + ret = krb5_dbe_cpw(handle->context, act_mkey, new_ks_tuple, new_n_ks_tuple, password, 0 /* increment kvno */, keepold, kdb); if (ret) @@ -1504,7 +1645,7 @@ kadm5_chpass_principal_3(void *server_handle, ret = k5_kadm5_hook_chpass(handle->context, handle->hook_handles, KADM5_HOOK_STAGE_PRECOMMIT, principal, keepold, - n_ks_tuple, ks_tuple, password); + new_n_ks_tuple, new_ks_tuple, password); if (ret) goto done; @@ -1513,9 +1654,10 @@ kadm5_chpass_principal_3(void *server_handle, (void) k5_kadm5_hook_chpass(handle->context, handle->hook_handles, KADM5_HOOK_STAGE_POSTCOMMIT, principal, - keepold, n_ks_tuple, ks_tuple, password); + keepold, new_n_ks_tuple, new_ks_tuple, password); ret = KADM5_OK; done: + free(new_ks_tuple); if (!hist_added && hist.key_data) free_history_entry(handle->context, &hist); kdb_free_entry(handle, kdb, &adb); @@ -1554,39 +1696,41 @@ kadm5_randkey_principal_3(void *server_handle, int ret, last_pwd, have_pol = 0; kadm5_server_handle_t handle = server_handle; krb5_keyblock *act_mkey; + int new_n_ks_tuple = 0; + krb5_key_salt_tuple *new_ks_tuple = NULL; if (keyblocks) *keyblocks = NULL; CHECK_HANDLE(server_handle); - /* Use default keysalts if caller did not provide any. */ - if (n_ks_tuple == 0) { - ks_tuple = handle->params.keysalts; - n_ks_tuple = handle->params.num_keysalts; - } - krb5_clear_error_message(handle->context); if (principal == NULL) return EINVAL; + + if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) + return(ret); + + ret = apply_keysalt_policy(handle, adb.policy, n_ks_tuple, ks_tuple, + &new_n_ks_tuple, &new_ks_tuple); + if (ret) + goto done; + if (krb5_principal_compare(handle->context, principal, hist_princ)) { /* If changing the history entry, the new entry must have exactly one * key. */ if (keepold) return KADM5_PROTECT_PRINCIPAL; - n_ks_tuple = 1; + new_n_ks_tuple = 1; } - if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) - return(ret); - ret = krb5_dbe_find_act_mkey(handle->context, active_mkey_list, NULL, &act_mkey); if (ret) goto done; - ret = krb5_dbe_crk(handle->context, act_mkey, ks_tuple, n_ks_tuple, + ret = krb5_dbe_crk(handle->context, act_mkey, new_ks_tuple, new_n_ks_tuple, keepold, kdb); if (ret) goto done; @@ -1650,7 +1794,7 @@ kadm5_randkey_principal_3(void *server_handle, ret = k5_kadm5_hook_chpass(handle->context, handle->hook_handles, KADM5_HOOK_STAGE_PRECOMMIT, principal, keepold, - n_ks_tuple, ks_tuple, NULL); + new_n_ks_tuple, new_ks_tuple, NULL); if (ret) goto done; if ((ret = kdb_put_entry(handle, kdb, &adb))) @@ -1658,9 +1802,10 @@ kadm5_randkey_principal_3(void *server_handle, (void) k5_kadm5_hook_chpass(handle->context, handle->hook_handles, KADM5_HOOK_STAGE_POSTCOMMIT, principal, - keepold, n_ks_tuple, ks_tuple, NULL); + keepold, new_n_ks_tuple, new_ks_tuple, NULL); ret = KADM5_OK; done: + free(new_ks_tuple); kdb_free_entry(handle, kdb, &adb); if (have_pol) kadm5_free_policy_ent(handle->lhandle, &pol); @@ -1838,6 +1983,24 @@ kadm5_setkey_principal(void *server_handle, keyblocks, n_keys); } +/* Make key/salt list from keys for kadm5_setkey_principal_3() */ +static kadm5_ret_t +make_ks_from_keys(krb5_context context, int n_keys, krb5_keyblock *keyblocks, + krb5_key_salt_tuple **ks_tuple) +{ + int i; + + *ks_tuple = calloc(n_keys, sizeof(**ks_tuple)); + if (ks_tuple == NULL) + return ENOMEM; + + for (i = 0; i < n_keys; i++) { + (*ks_tuple)[i].ks_enctype = keyblocks[i].enctype; + (*ks_tuple)[i].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; + } + return 0; +} + kadm5_ret_t kadm5_setkey_principal_3(void *server_handle, krb5_principal principal, @@ -1862,6 +2025,7 @@ kadm5_setkey_principal_3(void *server_handle, krb5_key_data tmp_key_data; krb5_key_data *tptr; krb5_keyblock *act_mkey; + krb5_key_salt_tuple *ks_from_keys = NULL; CHECK_HANDLE(server_handle); @@ -1874,6 +2038,31 @@ kadm5_setkey_principal_3(void *server_handle, principal, hist_princ)) == TRUE)) return KADM5_PROTECT_PRINCIPAL; + if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) + return(ret); + + if (!n_ks_tuple) { + /* Apply policy to the key/salt types implied by the given keys */ + ret = make_ks_from_keys(handle->context, n_keys, keyblocks, + &ks_from_keys); + if (ret) + goto done; + ret = apply_keysalt_policy(handle, adb.policy, n_keys, ks_from_keys, + NULL, NULL); + free(ks_from_keys); + } else { + /* + * Apply policy to the given ks_tuples. Note that further below + * we enforce keyblocks[i].enctype == ks_tuple[i].ks_enctype for + * all i from 0 to n_keys, and that n_ks_tuple == n_keys if ks + * tuples are given. + */ + ret = apply_keysalt_policy(handle, adb.policy, n_ks_tuple, ks_tuple, + NULL, NULL); + } + if (ret) + goto done; + for (i = 0; i < n_keys; i++) { for (j = i+1; j < n_keys; j++) { if ((ret = krb5_c_enctype_compare(handle->context, @@ -1894,9 +2083,6 @@ kadm5_setkey_principal_3(void *server_handle, if (n_ks_tuple && n_ks_tuple != n_keys) return KADM5_SETKEY3_ETYPE_MISMATCH; - if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) - return(ret); - for (kvno = 0, i=0; i<kdb->n_key_data; i++) if (kdb->key_data[i].key_data_kvno > kvno) kvno = kdb->key_data[i].key_data_kvno; |
