2 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
7 #if !defined(lint) && !defined(__CODECENTER__)
8 static char *rcsid = "$Header$";
11 #include <sys/types.h>
13 #include <kadm5/admin.h>
19 #include "server_internal.h"
23 extern krb5_principal master_princ;
24 extern krb5_principal hist_princ;
25 extern krb5_keyblock master_keyblock;
26 extern krb5_keyblock hist_key;
27 extern krb5_db_entry master_db;
28 extern krb5_db_entry hist_db;
29 extern krb5_kvno hist_kvno;
31 static int decrypt_key_data(krb5_context context,
32 int n_key_data, krb5_key_data *key_data,
33 krb5_keyblock **keyblocks, int *n_keys);
36 * XXX Functions that ought to be in libkrb5.a, but aren't.
38 kadm5_ret_t krb5_copy_key_data_contents(context, from, to)
40 krb5_key_data *from, *to;
46 idx = (from->key_data_ver == 1 ? 1 : 2);
48 for (i = 0; i < idx; i++) {
49 if ( from->key_data_length[i] ) {
50 to->key_data_contents[i] = malloc(from->key_data_length[i]);
51 if (to->key_data_contents[i] == NULL) {
52 for (i = 0; i < idx; i++) {
53 if (to->key_data_contents[i]) {
54 memset(to->key_data_contents[i], 0,
55 to->key_data_length[i]);
56 free(to->key_data_contents[i]);
61 memcpy(to->key_data_contents[i], from->key_data_contents[i],
62 from->key_data_length[i]);
68 static krb5_tl_data *dup_tl_data(krb5_tl_data *tl)
72 n = (krb5_tl_data *) malloc(sizeof(krb5_tl_data));
75 n->tl_data_contents = malloc(tl->tl_data_length);
76 if (n->tl_data_contents == NULL) {
80 memcpy(n->tl_data_contents, tl->tl_data_contents, tl->tl_data_length);
81 n->tl_data_type = tl->tl_data_type;
82 n->tl_data_length = tl->tl_data_length;
83 n->tl_data_next = NULL;
87 /* This is in lib/kdb/kdb_cpw.c, but is static */
88 static void cleanup_key_data(context, count, data)
95 for (i = 0; i < count; i++)
96 for (j = 0; j < data[i].key_data_ver; j++)
97 if (data[i].key_data_length[j])
98 free(data[i].key_data_contents[j]);
103 kadm5_create_principal(void *server_handle,
104 kadm5_principal_ent_t entry, long mask,
108 kadm5_create_principal_3(server_handle, entry, mask,
112 kadm5_create_principal_3(void *server_handle,
113 kadm5_principal_ent_t entry, long mask,
114 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
118 osa_princ_ent_rec adb;
119 kadm5_policy_ent_rec polent;
121 krb5_tl_data *tl_data_orig, *tl_data_tail;
123 kadm5_server_handle_t handle = server_handle;
125 CHECK_HANDLE(server_handle);
128 * Argument sanity checking, and opening up the DB
130 if(!(mask & KADM5_PRINCIPAL) || (mask & KADM5_MOD_NAME) ||
131 (mask & KADM5_MOD_TIME) || (mask & KADM5_LAST_PWD_CHANGE) ||
132 (mask & KADM5_MKVNO) || (mask & KADM5_POLICY_CLR) ||
133 (mask & KADM5_AUX_ATTRIBUTES) || (mask & KADM5_KEY_DATA) ||
134 (mask & KADM5_LAST_SUCCESS) || (mask & KADM5_LAST_FAILED) ||
135 (mask & KADM5_FAIL_AUTH_COUNT))
136 return KADM5_BAD_MASK;
137 if((mask & ~ALL_PRINC_MASK))
138 return KADM5_BAD_MASK;
139 if (entry == (kadm5_principal_ent_t) NULL || password == NULL)
143 * Check to see if the principal exists
145 ret = kdb_get_entry(handle, entry->principal, &kdb, &adb);
148 case KADM5_UNK_PRINC:
151 kdb_free_entry(handle, &kdb, &adb);
157 memset(&kdb, 0, sizeof(krb5_db_entry));
158 memset(&adb, 0, sizeof(osa_princ_ent_rec));
161 * If a policy was specified, load it.
162 * If we can not find the one specified return an error
164 if ((mask & KADM5_POLICY)) {
165 if ((ret = kadm5_get_policy(handle->lhandle, entry->policy,
166 &polent)) != KADM5_OK) {
168 return KADM5_BAD_POLICY;
173 if ((ret = passwd_check(handle, password, (mask & KADM5_POLICY),
174 &polent, entry->principal))) {
175 if (mask & KADM5_POLICY)
176 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
180 * Start populating the various DB fields, using the
181 * "defaults" for fields that were not specified by the
184 if ((ret = krb5_timeofday(handle->context, &now))) {
185 if (mask & KADM5_POLICY)
186 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
190 kdb.magic = KRB5_KDB_MAGIC_NUMBER;
191 kdb.len = KRB5_KDB_V1_BASE_LENGTH; /* gag me with a chainsaw */
193 if ((mask & KADM5_ATTRIBUTES))
194 kdb.attributes = entry->attributes;
196 kdb.attributes = handle->params.flags;
198 if ((mask & KADM5_MAX_LIFE))
199 kdb.max_life = entry->max_life;
201 kdb.max_life = handle->params.max_life;
203 if (mask & KADM5_MAX_RLIFE)
204 kdb.max_renewable_life = entry->max_renewable_life;
206 kdb.max_renewable_life = handle->params.max_rlife;
208 if ((mask & KADM5_PRINC_EXPIRE_TIME))
209 kdb.expiration = entry->princ_expire_time;
211 kdb.expiration = handle->params.expiration;
213 kdb.pw_expiration = 0;
214 if ((mask & KADM5_POLICY)) {
215 if(polent.pw_max_life)
216 kdb.pw_expiration = now + polent.pw_max_life;
218 kdb.pw_expiration = 0;
220 if ((mask & KADM5_PW_EXPIRATION))
221 kdb.pw_expiration = entry->pw_expiration;
223 kdb.last_success = 0;
225 kdb.fail_auth_count = 0;
227 /* this is kind of gross, but in order to free the tl data, I need
228 to free the entire kdb entry, and that will try to free the
231 if ((ret = krb5_copy_principal(handle->context,
232 entry->principal, &(kdb.princ)))) {
233 if (mask & KADM5_POLICY)
234 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
238 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now))) {
239 krb5_dbe_free_contents(handle->context, &kdb);
240 if (mask & KADM5_POLICY)
241 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
245 /* initialize the keys */
247 if ((ret = krb5_dbe_cpw(handle->context, &master_keyblock,
248 n_ks_tuple?ks_tuple:handle->params.keysalts,
249 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
251 (mask & KADM5_KVNO)?entry->kvno:1,
253 krb5_dbe_free_contents(handle->context, &kdb);
254 if (mask & KADM5_POLICY)
255 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
259 /* populate the admin-server-specific fields. In the OV server,
260 this used to be in a separate database. Since there's already
261 marshalling code for the admin fields, to keep things simple,
262 I'm going to keep it, and make all the admin stuff occupy a
263 single tl_data record, */
265 adb.admin_history_kvno = hist_kvno;
266 if ((mask & KADM5_POLICY)) {
267 adb.aux_attributes = KADM5_POLICY;
269 /* this does *not* need to be strdup'ed, because adb is xdr */
270 /* encoded in osa_adb_create_princ, and not ever freed */
272 adb.policy = entry->policy;
275 /* increment the policy ref count, if any */
277 if ((mask & KADM5_POLICY)) {
278 polent.policy_refcnt++;
279 if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent,
282 krb5_dbe_free_contents(handle->context, &kdb);
283 if (mask & KADM5_POLICY)
284 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
289 if (mask & KADM5_TL_DATA) {
290 /* splice entry->tl_data onto the front of kdb.tl_data */
291 tl_data_orig = kdb.tl_data;
292 for (tl_data_tail = entry->tl_data; tl_data_tail->tl_data_next;
293 tl_data_tail = tl_data_tail->tl_data_next)
295 tl_data_tail->tl_data_next = kdb.tl_data;
296 kdb.tl_data = entry->tl_data;
299 /* store the new db entry */
300 ret = kdb_put_entry(handle, &kdb, &adb);
302 if (mask & KADM5_TL_DATA) {
303 /* remove entry->tl_data from the front of kdb.tl_data */
304 tl_data_tail->tl_data_next = NULL;
305 kdb.tl_data = tl_data_orig;
308 krb5_dbe_free_contents(handle->context, &kdb);
311 if ((mask & KADM5_POLICY)) {
312 /* decrement the policy ref count */
314 polent.policy_refcnt--;
316 * if this fails, there's nothing we can do anyway. the
317 * policy refcount wil be too high.
319 (void) kadm5_modify_policy_internal(handle->lhandle, &polent,
323 if (mask & KADM5_POLICY)
324 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
328 if (mask & KADM5_POLICY)
329 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
336 kadm5_delete_principal(void *server_handle, krb5_principal principal)
339 kadm5_policy_ent_rec polent;
341 osa_princ_ent_rec adb;
342 kadm5_server_handle_t handle = server_handle;
344 CHECK_HANDLE(server_handle);
346 if (principal == NULL)
349 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
352 if ((adb.aux_attributes & KADM5_POLICY)) {
353 if ((ret = kadm5_get_policy(handle->lhandle,
354 adb.policy, &polent))
356 polent.policy_refcnt--;
357 if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent,
360 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
361 kdb_free_entry(handle, &kdb, &adb);
365 if ((ret = kadm5_free_policy_ent(handle->lhandle, &polent))) {
366 kdb_free_entry(handle, &kdb, &adb);
371 ret = kdb_delete_entry(handle, principal);
373 kdb_free_entry(handle, &kdb, &adb);
379 kadm5_modify_principal(void *server_handle,
380 kadm5_principal_ent_t entry, long mask)
383 kadm5_policy_ent_rec npol, opol;
384 int have_npol = 0, have_opol = 0;
386 krb5_tl_data *tl_data_orig;
387 osa_princ_ent_rec adb;
388 kadm5_server_handle_t handle = server_handle;
390 CHECK_HANDLE(server_handle);
392 if((mask & KADM5_PRINCIPAL) || (mask & KADM5_LAST_PWD_CHANGE) ||
393 (mask & KADM5_MOD_TIME) || (mask & KADM5_MOD_NAME) ||
394 (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) ||
395 (mask & KADM5_KEY_DATA) || (mask & KADM5_LAST_SUCCESS) ||
396 (mask & KADM5_LAST_FAILED))
397 return KADM5_BAD_MASK;
398 if((mask & ~ALL_PRINC_MASK))
399 return KADM5_BAD_MASK;
400 if((mask & KADM5_POLICY) && (mask & KADM5_POLICY_CLR))
401 return KADM5_BAD_MASK;
402 if(entry == (kadm5_principal_ent_t) NULL)
404 if (mask & KADM5_TL_DATA) {
405 tl_data_orig = entry->tl_data;
406 while (tl_data_orig) {
407 if (tl_data_orig->tl_data_type < 256)
408 return KADM5_BAD_TL_TYPE;
409 tl_data_orig = tl_data_orig->tl_data_next;
413 ret = kdb_get_entry(handle, entry->principal, &kdb, &adb);
418 * This is pretty much the same as create ...
421 if ((mask & KADM5_POLICY)) {
422 /* get the new policy */
423 ret = kadm5_get_policy(handle->lhandle, entry->policy, &npol);
427 ret = KADM5_BAD_POLICY;
429 case KADM5_UNK_POLICY:
430 case KADM5_BAD_POLICY:
431 ret = KADM5_UNK_POLICY;
438 /* if we already have a policy, get it to decrement the refcnt */
439 if(adb.aux_attributes & KADM5_POLICY) {
440 /* ... but not if the old and new are the same */
441 if(strcmp(adb.policy, entry->policy)) {
442 ret = kadm5_get_policy(handle->lhandle,
446 case KADM5_BAD_POLICY:
447 case KADM5_UNK_POLICY:
451 opol.policy_refcnt--;
457 npol.policy_refcnt++;
459 } else npol.policy_refcnt++;
461 /* set us up to use the new policy */
462 adb.aux_attributes |= KADM5_POLICY;
465 adb.policy = strdup(entry->policy);
467 /* set pw_max_life based on new policy */
468 if (npol.pw_max_life) {
469 ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb,
470 &(kdb.pw_expiration));
473 kdb.pw_expiration += npol.pw_max_life;
475 kdb.pw_expiration = 0;
479 if ((mask & KADM5_POLICY_CLR) &&
480 (adb.aux_attributes & KADM5_POLICY)) {
481 ret = kadm5_get_policy(handle->lhandle, adb.policy, &opol);
484 case KADM5_BAD_POLICY:
485 case KADM5_UNK_POLICY:
494 adb.aux_attributes &= ~KADM5_POLICY;
495 kdb.pw_expiration = 0;
496 opol.policy_refcnt--;
504 if (((mask & KADM5_POLICY) || (mask & KADM5_POLICY_CLR)) &&
507 kadm5_modify_policy_internal(handle->lhandle, &opol,
508 KADM5_REF_COUNT))) ||
511 kadm5_modify_policy_internal(handle->lhandle, &npol,
515 if ((mask & KADM5_ATTRIBUTES))
516 kdb.attributes = entry->attributes;
517 if ((mask & KADM5_MAX_LIFE))
518 kdb.max_life = entry->max_life;
519 if ((mask & KADM5_PRINC_EXPIRE_TIME))
520 kdb.expiration = entry->princ_expire_time;
521 if (mask & KADM5_PW_EXPIRATION)
522 kdb.pw_expiration = entry->pw_expiration;
523 if (mask & KADM5_MAX_RLIFE)
524 kdb.max_renewable_life = entry->max_renewable_life;
525 if (mask & KADM5_FAIL_AUTH_COUNT)
526 kdb.fail_auth_count = entry->fail_auth_count;
528 if((mask & KADM5_KVNO)) {
529 for (i = 0; i < kdb.n_key_data; i++)
530 kdb.key_data[i].key_data_kvno = entry->kvno;
533 if (mask & KADM5_TL_DATA) {
534 krb5_tl_data *tl, *tl2;
536 * Replace kdb.tl_data with what was passed in. The
537 * KRB5_TL_KADM_DATA will be re-added (based on adb) by
538 * kdb_put_entry, below.
540 * Note that we have to duplicate the passed in tl_data
541 * before adding it to kdb. The reason is that kdb_put_entry
542 * will add its own tl_data entries that we will need to
543 * free, but we cannot free the caller's tl_data (an
544 * alternative would be to scan the tl_data after put_entry
545 * and only free those entries that were not passed in).
547 while (kdb.tl_data) {
548 tl = kdb.tl_data->tl_data_next;
549 free(kdb.tl_data->tl_data_contents);
554 kdb.n_tl_data = entry->n_tl_data;
556 tl2 = entry->tl_data;
558 tl = dup_tl_data(tl2);
559 tl->tl_data_next = kdb.tl_data;
561 tl2 = tl2->tl_data_next;
565 ret = kdb_put_entry(handle, &kdb, &adb);
571 ret2 = kadm5_free_policy_ent(handle->lhandle, &opol);
572 ret = ret ? ret : ret2;
575 ret2 = kadm5_free_policy_ent(handle->lhandle, &npol);
576 ret = ret ? ret : ret2;
578 kdb_free_entry(handle, &kdb, &adb);
583 kadm5_rename_principal(void *server_handle,
584 krb5_principal source, krb5_principal target)
587 osa_princ_ent_rec adb;
589 kadm5_server_handle_t handle = server_handle;
591 CHECK_HANDLE(server_handle);
593 if (source == NULL || target == NULL)
596 if ((ret = kdb_get_entry(handle, target, &kdb, &adb)) == 0) {
597 kdb_free_entry(handle, &kdb, &adb);
601 if ((ret = kdb_get_entry(handle, source, &kdb, &adb)))
604 /* this is kinda gross, but unavoidable */
606 for (i=0; i<kdb.n_key_data; i++) {
607 if ((kdb.key_data[i].key_data_ver == 1) ||
608 (kdb.key_data[i].key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL)) {
609 ret = KADM5_NO_RENAME_SALT;
614 krb5_free_principal(handle->context, kdb.princ);
615 ret = krb5_copy_principal(handle->context, target, &kdb.princ);
617 kdb.princ = NULL; /* so freeing the dbe doesn't lose */
621 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
624 ret = kdb_delete_entry(handle, source);
627 kdb_free_entry(handle, &kdb, &adb);
632 kadm5_get_principal(void *server_handle, krb5_principal principal,
633 kadm5_principal_ent_t entry,
637 osa_princ_ent_rec adb;
638 osa_adb_ret_t ret = 0;
641 kadm5_server_handle_t handle = server_handle;
642 kadm5_principal_ent_rec entry_local, *entry_orig;
644 CHECK_HANDLE(server_handle);
647 * In version 1, all the defined fields are always returned.
648 * entry is a pointer to a kadm5_principal_ent_t_v1 that should be
649 * filled with allocated memory.
651 if (handle->api_version == KADM5_API_VERSION_1) {
652 mask = KADM5_PRINCIPAL_NORMAL_MASK;
654 entry = &entry_local;
659 memset((char *) entry, 0, sizeof(*entry));
661 if (principal == NULL)
664 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
667 if ((mask & KADM5_POLICY) &&
668 adb.policy && (adb.aux_attributes & KADM5_POLICY)) {
669 if ((entry->policy = (char *) malloc(strlen(adb.policy) + 1)) == NULL) {
673 strcpy(entry->policy, adb.policy);
676 if (mask & KADM5_AUX_ATTRIBUTES)
677 entry->aux_attributes = adb.aux_attributes;
679 if ((mask & KADM5_PRINCIPAL) &&
680 (ret = krb5_copy_principal(handle->context, principal,
681 &entry->principal))) {
685 if (mask & KADM5_PRINC_EXPIRE_TIME)
686 entry->princ_expire_time = kdb.expiration;
688 if ((mask & KADM5_LAST_PWD_CHANGE) &&
689 (ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb,
690 &(entry->last_pwd_change)))) {
694 if (mask & KADM5_PW_EXPIRATION)
695 entry->pw_expiration = kdb.pw_expiration;
696 if (mask & KADM5_MAX_LIFE)
697 entry->max_life = kdb.max_life;
699 /* this is a little non-sensical because the function returns two */
700 /* values that must be checked separately against the mask */
701 if ((mask & KADM5_MOD_NAME) || (mask & KADM5_MOD_TIME)) {
702 ret = krb5_dbe_lookup_mod_princ_data(handle->context, &kdb,
709 if (! (mask & KADM5_MOD_TIME))
711 if (! (mask & KADM5_MOD_NAME)) {
712 krb5_free_principal(handle->context, entry->principal);
713 entry->principal = NULL;
717 if (mask & KADM5_ATTRIBUTES)
718 entry->attributes = kdb.attributes;
720 if (mask & KADM5_KVNO)
721 for (entry->kvno = 0, i=0; i<kdb.n_key_data; i++)
722 if (kdb.key_data[i].key_data_kvno > entry->kvno)
723 entry->kvno = kdb.key_data[i].key_data_kvno;
725 if (handle->api_version == KADM5_API_VERSION_2)
728 /* XXX I'll be damned if I know how to deal with this one --marc */
733 * The new fields that only exist in version 2 start here
735 if (handle->api_version == KADM5_API_VERSION_2) {
736 if (mask & KADM5_MAX_RLIFE)
737 entry->max_renewable_life = kdb.max_renewable_life;
738 if (mask & KADM5_LAST_SUCCESS)
739 entry->last_success = kdb.last_success;
740 if (mask & KADM5_LAST_FAILED)
741 entry->last_failed = kdb.last_failed;
742 if (mask & KADM5_FAIL_AUTH_COUNT)
743 entry->fail_auth_count = kdb.fail_auth_count;
744 if (mask & KADM5_TL_DATA) {
745 krb5_tl_data *tl, *tl2;
747 entry->tl_data = NULL;
751 if (tl->tl_data_type > 255) {
752 if ((tl2 = dup_tl_data(tl)) == NULL) {
756 tl2->tl_data_next = entry->tl_data;
757 entry->tl_data = tl2;
761 tl = tl->tl_data_next;
764 if (mask & KADM5_KEY_DATA) {
765 entry->n_key_data = kdb.n_key_data;
766 if(entry->n_key_data) {
767 entry->key_data = (krb5_key_data *)
768 malloc(entry->n_key_data*sizeof(krb5_key_data));
769 if (entry->key_data == NULL) {
774 entry->key_data = NULL;
776 for (i = 0; i < entry->n_key_data; i++)
777 ret = krb5_copy_key_data_contents(handle->context,
779 &entry->key_data[i]);
786 * If KADM5_API_VERSION_1, we return an allocated structure, and
787 * we need to convert the new structure back into the format the
788 * caller is expecting.
790 if (handle->api_version == KADM5_API_VERSION_1) {
791 kadm5_principal_ent_t_v1 newv1;
793 newv1 = ((kadm5_principal_ent_t_v1) calloc(1, sizeof(*newv1)));
799 newv1->principal = entry->principal;
800 newv1->princ_expire_time = entry->princ_expire_time;
801 newv1->last_pwd_change = entry->last_pwd_change;
802 newv1->pw_expiration = entry->pw_expiration;
803 newv1->max_life = entry->max_life;
804 newv1->mod_name = entry->mod_name;
805 newv1->mod_date = entry->mod_date;
806 newv1->attributes = entry->attributes;
807 newv1->kvno = entry->kvno;
808 newv1->mkvno = entry->mkvno;
809 newv1->policy = entry->policy;
810 newv1->aux_attributes = entry->aux_attributes;
812 *((kadm5_principal_ent_t_v1 *) entry_orig) = newv1;
818 if (ret && entry->principal)
819 krb5_free_principal(handle->context, entry->principal);
820 kdb_free_entry(handle, &kdb, &adb);
826 * Function: check_pw_reuse
828 * Purpose: Check if a key appears in a list of keys, in order to
829 * enforce password history.
833 * context (r) the krb5 context
834 * hist_keyblock (r) the key that hist_key_data is
836 * n_new_key_data (r) length of new_key_data
837 * new_key_data (r) keys to check against
838 * pw_hist_data, encrypted in hist_keyblock
839 * n_pw_hist_data (r) length of pw_hist_data
840 * pw_hist_data (r) passwords to check new_key_data against
843 * For each new_key in new_key_data:
844 * decrypt new_key with the master_keyblock
845 * for each password in pw_hist_data:
846 * for each hist_key in password:
847 * decrypt hist_key with hist_keyblock
848 * compare the new_key and hist_key
850 * Returns krb5 errors, KADM5_PASS_RESUSE if a key in
851 * new_key_data is the same as a key in pw_hist_data, or 0.
854 check_pw_reuse(krb5_context context,
855 krb5_keyblock *hist_keyblock,
856 int n_new_key_data, krb5_key_data *new_key_data,
857 unsigned int n_pw_hist_data, osa_pw_hist_ent *pw_hist_data)
860 krb5_keyblock newkey, histkey;
863 for (x = 0; x < n_new_key_data; x++) {
864 ret = krb5_dbekd_decrypt_key_data(context,
870 for (y = 0; y < n_pw_hist_data; y++) {
871 for (z = 0; z < pw_hist_data[y].n_key_data; z++) {
872 ret = krb5_dbekd_decrypt_key_data(context,
874 &pw_hist_data[y].key_data[z],
879 if ((newkey.length == histkey.length) &&
880 (newkey.enctype == histkey.enctype) &&
881 (memcmp(newkey.contents, histkey.contents,
882 histkey.length) == 0)) {
883 krb5_free_keyblock_contents(context, &histkey);
884 krb5_free_keyblock_contents(context, &newkey);
886 return(KADM5_PASS_REUSE);
888 krb5_free_keyblock_contents(context, &histkey);
891 krb5_free_keyblock_contents(context, &newkey);
898 * Function: create_history_entry
900 * Purpose: Creates a password history entry from an array of
905 * context (r) krb5_context to use
906 * n_key_data (r) number of elements in key_data
907 * key_data (r) keys to add to the history entry
908 * hist (w) history entry to fill in
912 * hist->key_data is allocated to store n_key_data key_datas. Each
913 * element of key_data is decrypted with master_keyblock, re-encrypted
914 * in hist_key, and added to hist->key_data. hist->n_key_data is
918 int create_history_entry(krb5_context context, int n_key_data,
919 krb5_key_data *key_data, osa_pw_hist_ent *hist)
925 hist->key_data = (krb5_key_data*)malloc(n_key_data*sizeof(krb5_key_data));
926 if (hist->key_data == NULL)
928 memset(hist->key_data, 0, n_key_data*sizeof(krb5_key_data));
930 for (i = 0; i < n_key_data; i++) {
931 ret = krb5_dbekd_decrypt_key_data(context,
938 ret = krb5_dbekd_encrypt_key_data(context, &hist_key,
940 key_data[i].key_data_kvno,
945 krb5_free_keyblock_contents(context, &key);
946 /* krb5_free_keysalt(context, &salt); */
949 hist->n_key_data = n_key_data;
954 void free_history_entry(krb5_context context, osa_pw_hist_ent *hist)
958 for (i = 0; i < hist->n_key_data; i++)
959 krb5_free_key_data_contents(context, &hist->key_data[i]);
960 free(hist->key_data);
964 * Function: add_to_history
966 * Purpose: Adds a password to a principal's password history.
970 * context (r) krb5_context to use
971 * adb (r/w) admin principal entry to add keys to
972 * pol (r) adb's policy
973 * pw (r) keys for the password to add to adb's key history
977 * add_to_history adds a single password to adb's password history.
978 * pw contains n_key_data keys in its key_data, in storage should be
979 * allocated but not freed by the caller (XXX blech!).
981 * This function maintains adb->old_keys as a circular queue. It
982 * starts empty, and grows each time this function is called until it
983 * is pol->pw_history_num items long. adb->old_key_len holds the
984 * number of allocated entries in the array, and must therefore be [0,
985 * pol->pw_history_num). adb->old_key_next is the index into the
986 * array where the next element should be written, and must be [0,
989 #define KADM_MOD(x) (x + adb->old_key_next) % adb->old_key_len
990 static kadm5_ret_t add_to_history(krb5_context context,
992 kadm5_policy_ent_t pol,
995 osa_pw_hist_ent *histp;
998 /* A history of 1 means just check the current password */
999 if (pol->pw_history_num == 1)
1002 /* resize the adb->old_keys array if necessary */
1003 if (adb->old_key_len < pol->pw_history_num-1) {
1004 if (adb->old_keys == NULL) {
1005 adb->old_keys = (osa_pw_hist_ent *)
1006 malloc((adb->old_key_len + 1) * sizeof (osa_pw_hist_ent));
1008 adb->old_keys = (osa_pw_hist_ent *)
1009 realloc(adb->old_keys,
1010 (adb->old_key_len + 1) * sizeof (osa_pw_hist_ent));
1012 if (adb->old_keys == NULL)
1015 memset(&adb->old_keys[adb->old_key_len],0,sizeof(osa_pw_hist_ent));
1017 } else if (adb->old_key_len > pol->pw_history_num-1) {
1019 * The policy must have changed! Shrink the array.
1020 * Can't simply realloc() down, since it might be wrapped.
1021 * To understand the arithmetic below, note that we are
1022 * copying into new positions 0 .. N-1 from old positions
1023 * old_key_next-N .. old_key_next-1, modulo old_key_len,
1024 * where N = pw_history_num - 1 is the length of the
1025 * shortened list. Matt Crawford, FNAL
1028 histp = (osa_pw_hist_ent *)
1029 malloc((pol->pw_history_num - 1) * sizeof (osa_pw_hist_ent));
1031 for (i = 0; i < pol->pw_history_num - 1; i++) {
1032 /* We need the number we use the modulus operator on to be
1033 positive, so after subtracting pol->pw_history_num-1, we
1034 add back adb->old_key_len. */
1035 j = KADM_MOD(i - (pol->pw_history_num - 1) + adb->old_key_len);
1036 histp[i] = adb->old_keys[j];
1038 /* Now free the ones we don't keep (the oldest ones) */
1039 for (i = 0; i < adb->old_key_len - (pol->pw_history_num - 1); i++)
1040 for (j = 0; j < adb->old_keys[KADM_MOD(i)].n_key_data; j++)
1041 krb5_free_key_data_contents(context,
1042 &adb->old_keys[KADM_MOD(i)].key_data[j]);
1043 free((void *)adb->old_keys);
1044 adb->old_keys = histp;
1045 adb->old_key_len = pol->pw_history_num - 1;
1046 adb->old_key_next = 0;
1052 /* free the old pw history entry if it contains data */
1053 histp = &adb->old_keys[adb->old_key_next];
1054 for (i = 0; i < histp->n_key_data; i++)
1055 krb5_free_key_data_contents(context, &histp->key_data[i]);
1057 /* store the new entry */
1058 adb->old_keys[adb->old_key_next] = *pw;
1060 /* update the next pointer */
1061 if (++adb->old_key_next == pol->pw_history_num-1)
1062 adb->old_key_next = 0;
1069 kadm5_chpass_principal(void *server_handle,
1070 krb5_principal principal, char *password)
1073 kadm5_chpass_principal_3(server_handle, principal, FALSE,
1078 kadm5_chpass_principal_3(void *server_handle,
1079 krb5_principal principal, krb5_boolean keepold,
1080 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1084 kadm5_policy_ent_rec pol;
1085 osa_princ_ent_rec adb;
1086 krb5_db_entry kdb, kdb_save;
1087 int ret, ret2, last_pwd, hist_added;
1089 kadm5_server_handle_t handle = server_handle;
1090 osa_pw_hist_ent hist;
1092 CHECK_HANDLE(server_handle);
1095 memset(&hist, 0, sizeof(hist));
1097 if (principal == NULL || password == NULL)
1099 if ((krb5_principal_compare(handle->context,
1100 principal, hist_princ)) == TRUE)
1101 return KADM5_PROTECT_PRINCIPAL;
1103 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1106 /* we are going to need the current keys after the new keys are set */
1107 if ((ret = kdb_get_entry(handle, principal, &kdb_save, NULL))) {
1108 kdb_free_entry(handle, &kdb, &adb);
1112 if ((adb.aux_attributes & KADM5_POLICY)) {
1113 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &pol)))
1118 if ((ret = passwd_check(handle, password, adb.aux_attributes &
1119 KADM5_POLICY, &pol, principal)))
1122 ret = krb5_dbe_cpw(handle->context, &master_keyblock,
1123 n_ks_tuple?ks_tuple:handle->params.keysalts,
1124 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
1125 password, 0 /* increment kvno */,
1130 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1132 ret = krb5_timeofday(handle->context, &now);
1136 if ((adb.aux_attributes & KADM5_POLICY)) {
1137 /* the policy was loaded before */
1139 ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1146 * The spec says this check is overridden if the caller has
1147 * modify privilege. The admin server therefore makes this
1148 * check itself (in chpass_principal_wrapper, misc.c). A
1149 * local caller implicitly has all authorization bits.
1151 if ((now - last_pwd) < pol.pw_min_life &&
1152 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1153 ret = KADM5_PASS_TOOSOON;
1158 ret = create_history_entry(handle->context,
1159 kdb_save.n_key_data,
1160 kdb_save.key_data, &hist);
1164 ret = check_pw_reuse(handle->context, &hist_key,
1165 kdb.n_key_data, kdb.key_data,
1170 if (pol.pw_history_num > 1) {
1171 if (adb.admin_history_kvno != hist_kvno) {
1172 ret = KADM5_BAD_HIST_KEY;
1176 ret = check_pw_reuse(handle->context, &hist_key,
1177 kdb.n_key_data, kdb.key_data,
1178 adb.old_key_len, adb.old_keys);
1182 ret = add_to_history(handle->context, &adb, &pol, &hist);
1188 if (pol.pw_max_life)
1189 kdb.pw_expiration = now + pol.pw_max_life;
1191 kdb.pw_expiration = 0;
1193 kdb.pw_expiration = 0;
1196 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
1200 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1205 if (!hist_added && hist.key_data)
1206 free_history_entry(handle->context, &hist);
1207 kdb_free_entry(handle, &kdb, &adb);
1208 kdb_free_entry(handle, &kdb_save, NULL);
1209 krb5_dbe_free_contents(handle->context, &kdb);
1211 if (have_pol && (ret2 = kadm5_free_policy_ent(handle->lhandle, &pol))
1219 kadm5_randkey_principal(void *server_handle,
1220 krb5_principal principal,
1221 krb5_keyblock **keyblocks,
1225 kadm5_randkey_principal_3(server_handle, principal,
1230 kadm5_randkey_principal_3(void *server_handle,
1231 krb5_principal principal,
1232 krb5_boolean keepold,
1233 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1234 krb5_keyblock **keyblocks,
1238 osa_princ_ent_rec adb;
1240 kadm5_policy_ent_rec pol;
1241 krb5_key_data *key_data;
1242 int ret, last_pwd, have_pol = 0;
1243 kadm5_server_handle_t handle = server_handle;
1248 CHECK_HANDLE(server_handle);
1250 if (principal == NULL)
1252 if (hist_princ && /* this will be NULL when initializing the databse */
1253 ((krb5_principal_compare(handle->context,
1254 principal, hist_princ)) == TRUE))
1255 return KADM5_PROTECT_PRINCIPAL;
1257 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1260 ret = krb5_dbe_crk(handle->context, &master_keyblock,
1261 n_ks_tuple?ks_tuple:handle->params.keysalts,
1262 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
1268 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1270 ret = krb5_timeofday(handle->context, &now);
1274 if ((adb.aux_attributes & KADM5_POLICY)) {
1275 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1280 ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1287 * The spec says this check is overridden if the caller has
1288 * modify privilege. The admin server therefore makes this
1289 * check itself (in chpass_principal_wrapper, misc.c). A
1290 * local caller implicitly has all authorization bits.
1292 if((now - last_pwd) < pol.pw_min_life &&
1293 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1294 ret = KADM5_PASS_TOOSOON;
1299 if(pol.pw_history_num > 1) {
1300 if(adb.admin_history_kvno != hist_kvno) {
1301 ret = KADM5_BAD_HIST_KEY;
1305 ret = check_pw_reuse(handle->context, &hist_key,
1306 kdb.n_key_data, kdb.key_data,
1307 adb.old_key_len, adb.old_keys);
1311 if (pol.pw_max_life)
1312 kdb.pw_expiration = now + pol.pw_max_life;
1314 kdb.pw_expiration = 0;
1316 kdb.pw_expiration = 0;
1319 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
1324 if (handle->api_version == KADM5_API_VERSION_1) {
1325 /* Version 1 clients will expect to see a DES_CRC enctype. */
1326 ret = krb5_dbe_find_enctype(handle->context, &kdb,
1327 ENCTYPE_DES_CBC_CRC,
1332 ret = decrypt_key_data(handle->context, 1, key_data,
1337 ret = decrypt_key_data(handle->context,
1338 kdb.n_key_data, kdb.key_data,
1345 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1350 kdb_free_entry(handle, &kdb, &adb);
1352 kadm5_free_policy_ent(handle->lhandle, &pol);
1358 * kadm5_setv4key_principal:
1360 * Set only ONE key of the principal, removing all others. This key
1361 * must have the DES_CBC_CRC enctype and is entered as having the
1362 * krb4 salttype. This is to enable things like kadmind4 to work.
1365 kadm5_setv4key_principal(void *server_handle,
1366 krb5_principal principal,
1367 krb5_keyblock *keyblock)
1370 osa_princ_ent_rec adb;
1372 kadm5_policy_ent_rec pol;
1373 krb5_keysalt keysalt;
1374 int i, kvno, ret, have_pol = 0;
1378 kadm5_server_handle_t handle = server_handle;
1380 CHECK_HANDLE(server_handle);
1382 if (principal == NULL || keyblock == NULL)
1384 if (hist_princ && /* this will be NULL when initializing the databse */
1385 ((krb5_principal_compare(handle->context,
1386 principal, hist_princ)) == TRUE))
1387 return KADM5_PROTECT_PRINCIPAL;
1389 if (keyblock->enctype != ENCTYPE_DES_CBC_CRC)
1390 return KADM5_SETV4KEY_INVAL_ENCTYPE;
1392 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1395 for (kvno = 0, i=0; i<kdb.n_key_data; i++)
1396 if (kdb.key_data[i].key_data_kvno > kvno)
1397 kvno = kdb.key_data[i].key_data_kvno;
1399 if (kdb.key_data != NULL)
1400 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
1402 kdb.key_data = (krb5_key_data*)malloc(sizeof(krb5_key_data));
1403 if (kdb.key_data == NULL)
1405 memset(kdb.key_data, 0, sizeof(krb5_key_data));
1407 keysalt.type = KRB5_KDB_SALTTYPE_V4;
1408 /* XXX data.magic? */
1409 keysalt.data.length = 0;
1410 keysalt.data.data = NULL;
1412 ret = krb5_dbekd_encrypt_key_data(handle->context, &master_keyblock,
1413 keyblock, &keysalt, kvno + 1,
1419 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1421 ret = krb5_timeofday(handle->context, &now);
1425 if ((adb.aux_attributes & KADM5_POLICY)) {
1426 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1433 * The spec says this check is overridden if the caller has
1434 * modify privilege. The admin server therefore makes this
1435 * check itself (in chpass_principal_wrapper, misc.c). A
1436 * local caller implicitly has all authorization bits.
1438 if (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1441 if((now - last_pwd) < pol.pw_min_life &&
1442 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1443 ret = KADM5_PASS_TOOSOON;
1449 * Should we be checking/updating pw history here?
1451 if(pol.pw_history_num > 1) {
1452 if(adb.admin_history_kvno != hist_kvno) {
1453 ret = KADM5_BAD_HIST_KEY;
1457 if (ret = check_pw_reuse(handle->context,
1459 kdb.n_key_data, kdb.key_data,
1460 adb.old_key_len, adb.old_keys))
1465 if (pol.pw_max_life)
1466 kdb.pw_expiration = now + pol.pw_max_life;
1468 kdb.pw_expiration = 0;
1470 kdb.pw_expiration = 0;
1473 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
1477 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1482 kdb_free_entry(handle, &kdb, &adb);
1484 kadm5_free_policy_ent(handle->lhandle, &pol);
1490 kadm5_setkey_principal(void *server_handle,
1491 krb5_principal principal,
1492 krb5_keyblock *keyblocks,
1496 kadm5_setkey_principal_3(server_handle, principal,
1502 kadm5_setkey_principal_3(void *server_handle,
1503 krb5_principal principal,
1504 krb5_boolean keepold,
1505 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1506 krb5_keyblock *keyblocks,
1510 osa_princ_ent_rec adb;
1512 kadm5_policy_ent_rec pol;
1513 krb5_key_data *old_key_data;
1515 int i, j, kvno, ret, have_pol = 0;
1519 kadm5_server_handle_t handle = server_handle;
1520 krb5_boolean similar;
1521 krb5_keysalt keysalt;
1523 CHECK_HANDLE(server_handle);
1525 if (principal == NULL || keyblocks == NULL)
1527 if (hist_princ && /* this will be NULL when initializing the databse */
1528 ((krb5_principal_compare(handle->context,
1529 principal, hist_princ)) == TRUE))
1530 return KADM5_PROTECT_PRINCIPAL;
1532 for (i = 0; i < n_keys; i++) {
1533 for (j = i+1; j < n_keys; j++) {
1534 if ((ret = krb5_c_enctype_compare(handle->context,
1535 keyblocks[i].enctype,
1536 keyblocks[j].enctype,
1541 if (ks_tuple[i].ks_salttype == ks_tuple[j].ks_salttype)
1542 return KADM5_SETKEY_DUP_ENCTYPES;
1544 return KADM5_SETKEY_DUP_ENCTYPES;
1549 if (n_ks_tuple && n_ks_tuple != n_keys)
1550 return KADM5_SETKEY3_ETYPE_MISMATCH;
1552 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1555 for (kvno = 0, i=0; i<kdb.n_key_data; i++)
1556 if (kdb.key_data[i].key_data_kvno > kvno)
1557 kvno = kdb.key_data[i].key_data_kvno;
1560 old_key_data = kdb.key_data;
1561 n_old_keys = kdb.n_key_data;
1563 if (kdb.key_data != NULL)
1564 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
1566 old_key_data = NULL;
1569 kdb.key_data = (krb5_key_data*)malloc((n_keys+n_old_keys)
1570 *sizeof(krb5_key_data));
1571 if (kdb.key_data == NULL)
1573 memset(kdb.key_data, 0, (n_keys+n_old_keys)*sizeof(krb5_key_data));
1576 for (i = 0; i < n_keys; i++) {
1578 keysalt.type = ks_tuple[i].ks_salttype;
1579 keysalt.data.length = 0;
1580 keysalt.data.data = NULL;
1581 if (ks_tuple[i].ks_enctype != keyblocks[i].enctype) {
1582 cleanup_key_data(handle->context, kdb.n_key_data,
1584 return KADM5_SETKEY3_ETYPE_MISMATCH;
1587 ret = krb5_dbekd_encrypt_key_data(handle->context,
1590 n_ks_tuple ? &keysalt : NULL,
1594 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
1600 /* copy old key data if necessary */
1601 for (i = 0; i < n_old_keys; i++) {
1602 kdb.key_data[i+n_keys] = old_key_data[i];
1603 memset(&old_key_data[i], 0, sizeof (krb5_key_data));
1606 /* assert(kdb.n_key_data == n_keys + n_old_keys) */
1607 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1609 if ((ret = krb5_timeofday(handle->context, &now)))
1612 if ((adb.aux_attributes & KADM5_POLICY)) {
1613 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1620 * The spec says this check is overridden if the caller has
1621 * modify privilege. The admin server therefore makes this
1622 * check itself (in chpass_principal_wrapper, misc.c). A
1623 * local caller implicitly has all authorization bits.
1625 if (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1628 if((now - last_pwd) < pol.pw_min_life &&
1629 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1630 ret = KADM5_PASS_TOOSOON;
1636 * Should we be checking/updating pw history here?
1638 if(pol.pw_history_num > 1) {
1639 if(adb.admin_history_kvno != hist_kvno) {
1640 ret = KADM5_BAD_HIST_KEY;
1644 if (ret = check_pw_reuse(handle->context,
1646 kdb.n_key_data, kdb.key_data,
1647 adb.old_key_len, adb.old_keys))
1652 if (pol.pw_max_life)
1653 kdb.pw_expiration = now + pol.pw_max_life;
1655 kdb.pw_expiration = 0;
1657 kdb.pw_expiration = 0;
1660 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now)))
1663 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1668 kdb_free_entry(handle, &kdb, &adb);
1670 kadm5_free_policy_ent(handle->lhandle, &pol);
1676 * Allocate an array of n_key_data krb5_keyblocks, fill in each
1677 * element with the results of decrypting the nth key in key_data with
1678 * master_keyblock, and if n_keys is not NULL fill it in with the
1679 * number of keys decrypted.
1681 static int decrypt_key_data(krb5_context context,
1682 int n_key_data, krb5_key_data *key_data,
1683 krb5_keyblock **keyblocks, int *n_keys)
1685 krb5_keyblock *keys;
1688 keys = (krb5_keyblock *) malloc(n_key_data*sizeof(krb5_keyblock));
1691 memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock));
1693 for (i = 0; i < n_key_data; i++) {
1694 ret = krb5_dbekd_decrypt_key_data(context, &master_keyblock,
1699 memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock));
1707 *n_keys = n_key_data;
1713 * Function: kadm5_decrypt_key
1715 * Purpose: Retrieves and decrypts a principal key.
1719 * server_handle (r) kadm5 handle
1720 * entry (r) principal retrieved with kadm5_get_principal
1721 * ktype (r) enctype to search for, or -1 to ignore
1722 * stype (r) salt type to search for, or -1 to ignore
1723 * kvno (r) kvno to search for, -1 for max, 0 for max
1724 * only if it also matches ktype and stype
1725 * keyblock (w) keyblock to fill in
1726 * keysalt (w) keysalt to fill in, or NULL
1727 * kvnop (w) kvno to fill in, or NULL
1729 * Effects: Searches the key_data array of entry, which must have been
1730 * retrived with kadm5_get_principal with the KADM5_KEY_DATA mask, to
1731 * find a key with a specified enctype, salt type, and kvno in a
1732 * principal entry. If not found, return ENOENT. Otherwise, decrypt
1733 * it with the master key, and return the key in keyblock, the salt
1734 * in salttype, and the key version number in kvno.
1736 * If ktype or stype is -1, it is ignored for the search. If kvno is
1737 * -1, ktype and stype are ignored and the key with the max kvno is
1738 * returned. If kvno is 0, only the key with the max kvno is returned
1739 * and only if it matches the ktype and stype; otherwise, ENOENT is
1742 kadm5_ret_t kadm5_decrypt_key(void *server_handle,
1743 kadm5_principal_ent_t entry, krb5_int32
1744 ktype, krb5_int32 stype, krb5_int32
1745 kvno, krb5_keyblock *keyblock,
1746 krb5_keysalt *keysalt, int *kvnop)
1748 kadm5_server_handle_t handle = server_handle;
1749 krb5_db_entry dbent;
1750 krb5_key_data *key_data;
1753 CHECK_HANDLE(server_handle);
1755 if (entry->n_key_data == 0 || entry->key_data == NULL)
1758 /* find_enctype only uses these two fields */
1759 dbent.n_key_data = entry->n_key_data;
1760 dbent.key_data = entry->key_data;
1761 if ((ret = krb5_dbe_find_enctype(handle->context, &dbent, ktype,
1762 stype, kvno, &key_data)))
1765 if ((ret = krb5_dbekd_decrypt_key_data(handle->context,
1766 &master_keyblock, key_data,
1767 keyblock, keysalt)))
1771 * Coerce the enctype of the output keyblock in case we got an
1772 * inexact match on the enctype; this behavior will go away when
1773 * the key storage architecture gets redesigned for 1.3.
1775 keyblock->enctype = ktype;
1778 *kvnop = key_data->key_data_kvno;