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"
22 #ifdef USE_PASSWORD_SERVER
26 extern krb5_principal master_princ;
27 extern krb5_principal hist_princ;
28 extern krb5_keyblock master_keyblock;
29 extern krb5_keyblock hist_key;
30 extern krb5_db_entry master_db;
31 extern krb5_db_entry hist_db;
32 extern krb5_kvno hist_kvno;
34 static int decrypt_key_data(krb5_context context,
35 int n_key_data, krb5_key_data *key_data,
36 krb5_keyblock **keyblocks, int *n_keys);
39 * XXX Functions that ought to be in libkrb5.a, but aren't.
41 kadm5_ret_t krb5_copy_key_data_contents(context, from, to)
43 krb5_key_data *from, *to;
49 idx = (from->key_data_ver == 1 ? 1 : 2);
51 for (i = 0; i < idx; i++) {
52 if ( from->key_data_length[i] ) {
53 to->key_data_contents[i] = malloc(from->key_data_length[i]);
54 if (to->key_data_contents[i] == NULL) {
55 for (i = 0; i < idx; i++) {
56 if (to->key_data_contents[i]) {
57 memset(to->key_data_contents[i], 0,
58 to->key_data_length[i]);
59 free(to->key_data_contents[i]);
64 memcpy(to->key_data_contents[i], from->key_data_contents[i],
65 from->key_data_length[i]);
71 static krb5_tl_data *dup_tl_data(krb5_tl_data *tl)
75 n = (krb5_tl_data *) malloc(sizeof(krb5_tl_data));
78 n->tl_data_contents = malloc(tl->tl_data_length);
79 if (n->tl_data_contents == NULL) {
83 memcpy(n->tl_data_contents, tl->tl_data_contents, tl->tl_data_length);
84 n->tl_data_type = tl->tl_data_type;
85 n->tl_data_length = tl->tl_data_length;
86 n->tl_data_next = NULL;
90 /* This is in lib/kdb/kdb_cpw.c, but is static */
91 static void cleanup_key_data(context, count, data)
98 for (i = 0; i < count; i++)
99 for (j = 0; j < data[i].key_data_ver; j++)
100 if (data[i].key_data_length[j])
101 free(data[i].key_data_contents[j]);
106 kadm5_create_principal(void *server_handle,
107 kadm5_principal_ent_t entry, long mask,
111 kadm5_create_principal_3(server_handle, entry, mask,
115 kadm5_create_principal_3(void *server_handle,
116 kadm5_principal_ent_t entry, long mask,
117 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
121 osa_princ_ent_rec adb;
122 kadm5_policy_ent_rec polent;
124 krb5_tl_data *tl_data_orig, *tl_data_tail;
126 kadm5_server_handle_t handle = server_handle;
128 CHECK_HANDLE(server_handle);
131 * Argument sanity checking, and opening up the DB
133 if(!(mask & KADM5_PRINCIPAL) || (mask & KADM5_MOD_NAME) ||
134 (mask & KADM5_MOD_TIME) || (mask & KADM5_LAST_PWD_CHANGE) ||
135 (mask & KADM5_MKVNO) || (mask & KADM5_POLICY_CLR) ||
136 (mask & KADM5_AUX_ATTRIBUTES) || (mask & KADM5_KEY_DATA) ||
137 (mask & KADM5_LAST_SUCCESS) || (mask & KADM5_LAST_FAILED) ||
138 (mask & KADM5_FAIL_AUTH_COUNT))
139 return KADM5_BAD_MASK;
140 if((mask & ~ALL_PRINC_MASK))
141 return KADM5_BAD_MASK;
142 if (entry == (kadm5_principal_ent_t) NULL || password == NULL)
146 * Check to see if the principal exists
148 ret = kdb_get_entry(handle, entry->principal, &kdb, &adb);
151 case KADM5_UNK_PRINC:
154 kdb_free_entry(handle, &kdb, &adb);
160 memset(&kdb, 0, sizeof(krb5_db_entry));
161 memset(&adb, 0, sizeof(osa_princ_ent_rec));
164 * If a policy was specified, load it.
165 * If we can not find the one specified return an error
167 if ((mask & KADM5_POLICY)) {
168 if ((ret = kadm5_get_policy(handle->lhandle, entry->policy,
169 &polent)) != KADM5_OK) {
171 return KADM5_BAD_POLICY;
176 if ((ret = passwd_check(handle, password, (mask & KADM5_POLICY),
177 &polent, entry->principal))) {
178 if (mask & KADM5_POLICY)
179 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
183 * Start populating the various DB fields, using the
184 * "defaults" for fields that were not specified by the
187 if ((ret = krb5_timeofday(handle->context, &now))) {
188 if (mask & KADM5_POLICY)
189 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
193 kdb.magic = KRB5_KDB_MAGIC_NUMBER;
194 kdb.len = KRB5_KDB_V1_BASE_LENGTH; /* gag me with a chainsaw */
196 if ((mask & KADM5_ATTRIBUTES))
197 kdb.attributes = entry->attributes;
199 kdb.attributes = handle->params.flags;
201 if ((mask & KADM5_MAX_LIFE))
202 kdb.max_life = entry->max_life;
204 kdb.max_life = handle->params.max_life;
206 if (mask & KADM5_MAX_RLIFE)
207 kdb.max_renewable_life = entry->max_renewable_life;
209 kdb.max_renewable_life = handle->params.max_rlife;
211 if ((mask & KADM5_PRINC_EXPIRE_TIME))
212 kdb.expiration = entry->princ_expire_time;
214 kdb.expiration = handle->params.expiration;
216 kdb.pw_expiration = 0;
217 if ((mask & KADM5_POLICY)) {
218 if(polent.pw_max_life)
219 kdb.pw_expiration = now + polent.pw_max_life;
221 kdb.pw_expiration = 0;
223 if ((mask & KADM5_PW_EXPIRATION))
224 kdb.pw_expiration = entry->pw_expiration;
226 kdb.last_success = 0;
228 kdb.fail_auth_count = 0;
230 /* this is kind of gross, but in order to free the tl data, I need
231 to free the entire kdb entry, and that will try to free the
234 if ((ret = krb5_copy_principal(handle->context,
235 entry->principal, &(kdb.princ)))) {
236 if (mask & KADM5_POLICY)
237 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
241 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now))) {
242 krb5_dbe_free_contents(handle->context, &kdb);
243 if (mask & KADM5_POLICY)
244 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
248 /* initialize the keys */
250 if ((ret = krb5_dbe_cpw(handle->context, &master_keyblock,
251 n_ks_tuple?ks_tuple:handle->params.keysalts,
252 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
254 (mask & KADM5_KVNO)?entry->kvno:1,
256 krb5_dbe_free_contents(handle->context, &kdb);
257 if (mask & KADM5_POLICY)
258 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
262 /* populate the admin-server-specific fields. In the OV server,
263 this used to be in a separate database. Since there's already
264 marshalling code for the admin fields, to keep things simple,
265 I'm going to keep it, and make all the admin stuff occupy a
266 single tl_data record, */
268 adb.admin_history_kvno = hist_kvno;
269 if ((mask & KADM5_POLICY)) {
270 adb.aux_attributes = KADM5_POLICY;
272 /* this does *not* need to be strdup'ed, because adb is xdr */
273 /* encoded in osa_adb_create_princ, and not ever freed */
275 adb.policy = entry->policy;
278 /* increment the policy ref count, if any */
280 if ((mask & KADM5_POLICY)) {
281 polent.policy_refcnt++;
282 if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent,
285 krb5_dbe_free_contents(handle->context, &kdb);
286 if (mask & KADM5_POLICY)
287 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
292 if (mask & KADM5_TL_DATA) {
293 /* splice entry->tl_data onto the front of kdb.tl_data */
294 tl_data_orig = kdb.tl_data;
295 for (tl_data_tail = entry->tl_data; tl_data_tail->tl_data_next;
296 tl_data_tail = tl_data_tail->tl_data_next)
298 tl_data_tail->tl_data_next = kdb.tl_data;
299 kdb.tl_data = entry->tl_data;
302 /* store the new db entry */
303 ret = kdb_put_entry(handle, &kdb, &adb);
305 if (mask & KADM5_TL_DATA) {
306 /* remove entry->tl_data from the front of kdb.tl_data */
307 tl_data_tail->tl_data_next = NULL;
308 kdb.tl_data = tl_data_orig;
311 krb5_dbe_free_contents(handle->context, &kdb);
314 if ((mask & KADM5_POLICY)) {
315 /* decrement the policy ref count */
317 polent.policy_refcnt--;
319 * if this fails, there's nothing we can do anyway. the
320 * policy refcount wil be too high.
322 (void) kadm5_modify_policy_internal(handle->lhandle, &polent,
326 if (mask & KADM5_POLICY)
327 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
331 if (mask & KADM5_POLICY)
332 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
339 kadm5_delete_principal(void *server_handle, krb5_principal principal)
342 kadm5_policy_ent_rec polent;
344 osa_princ_ent_rec adb;
345 kadm5_server_handle_t handle = server_handle;
347 CHECK_HANDLE(server_handle);
349 if (principal == NULL)
352 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
355 if ((adb.aux_attributes & KADM5_POLICY)) {
356 if ((ret = kadm5_get_policy(handle->lhandle,
357 adb.policy, &polent))
359 polent.policy_refcnt--;
360 if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent,
363 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
364 kdb_free_entry(handle, &kdb, &adb);
368 if ((ret = kadm5_free_policy_ent(handle->lhandle, &polent))) {
369 kdb_free_entry(handle, &kdb, &adb);
374 ret = kdb_delete_entry(handle, principal);
376 kdb_free_entry(handle, &kdb, &adb);
382 kadm5_modify_principal(void *server_handle,
383 kadm5_principal_ent_t entry, long mask)
386 kadm5_policy_ent_rec npol, opol;
387 int have_npol = 0, have_opol = 0;
389 krb5_tl_data *tl_data_orig;
390 osa_princ_ent_rec adb;
391 kadm5_server_handle_t handle = server_handle;
393 CHECK_HANDLE(server_handle);
395 if((mask & KADM5_PRINCIPAL) || (mask & KADM5_LAST_PWD_CHANGE) ||
396 (mask & KADM5_MOD_TIME) || (mask & KADM5_MOD_NAME) ||
397 (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) ||
398 (mask & KADM5_KEY_DATA) || (mask & KADM5_LAST_SUCCESS) ||
399 (mask & KADM5_LAST_FAILED))
400 return KADM5_BAD_MASK;
401 if((mask & ~ALL_PRINC_MASK))
402 return KADM5_BAD_MASK;
403 if((mask & KADM5_POLICY) && (mask & KADM5_POLICY_CLR))
404 return KADM5_BAD_MASK;
405 if(entry == (kadm5_principal_ent_t) NULL)
407 if (mask & KADM5_TL_DATA) {
408 tl_data_orig = entry->tl_data;
409 while (tl_data_orig) {
410 if (tl_data_orig->tl_data_type < 256)
411 return KADM5_BAD_TL_TYPE;
412 tl_data_orig = tl_data_orig->tl_data_next;
416 ret = kdb_get_entry(handle, entry->principal, &kdb, &adb);
421 * This is pretty much the same as create ...
424 if ((mask & KADM5_POLICY)) {
425 /* get the new policy */
426 ret = kadm5_get_policy(handle->lhandle, entry->policy, &npol);
430 ret = KADM5_BAD_POLICY;
432 case KADM5_UNK_POLICY:
433 case KADM5_BAD_POLICY:
434 ret = KADM5_UNK_POLICY;
441 /* if we already have a policy, get it to decrement the refcnt */
442 if(adb.aux_attributes & KADM5_POLICY) {
443 /* ... but not if the old and new are the same */
444 if(strcmp(adb.policy, entry->policy)) {
445 ret = kadm5_get_policy(handle->lhandle,
449 case KADM5_BAD_POLICY:
450 case KADM5_UNK_POLICY:
454 opol.policy_refcnt--;
460 npol.policy_refcnt++;
462 } else npol.policy_refcnt++;
464 /* set us up to use the new policy */
465 adb.aux_attributes |= KADM5_POLICY;
468 adb.policy = strdup(entry->policy);
470 /* set pw_max_life based on new policy */
471 if (npol.pw_max_life) {
472 ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb,
473 &(kdb.pw_expiration));
476 kdb.pw_expiration += npol.pw_max_life;
478 kdb.pw_expiration = 0;
482 if ((mask & KADM5_POLICY_CLR) &&
483 (adb.aux_attributes & KADM5_POLICY)) {
484 ret = kadm5_get_policy(handle->lhandle, adb.policy, &opol);
487 case KADM5_BAD_POLICY:
488 case KADM5_UNK_POLICY:
497 adb.aux_attributes &= ~KADM5_POLICY;
498 kdb.pw_expiration = 0;
499 opol.policy_refcnt--;
507 if (((mask & KADM5_POLICY) || (mask & KADM5_POLICY_CLR)) &&
510 kadm5_modify_policy_internal(handle->lhandle, &opol,
511 KADM5_REF_COUNT))) ||
514 kadm5_modify_policy_internal(handle->lhandle, &npol,
518 if ((mask & KADM5_ATTRIBUTES))
519 kdb.attributes = entry->attributes;
520 if ((mask & KADM5_MAX_LIFE))
521 kdb.max_life = entry->max_life;
522 if ((mask & KADM5_PRINC_EXPIRE_TIME))
523 kdb.expiration = entry->princ_expire_time;
524 if (mask & KADM5_PW_EXPIRATION)
525 kdb.pw_expiration = entry->pw_expiration;
526 if (mask & KADM5_MAX_RLIFE)
527 kdb.max_renewable_life = entry->max_renewable_life;
528 if (mask & KADM5_FAIL_AUTH_COUNT)
529 kdb.fail_auth_count = entry->fail_auth_count;
531 if((mask & KADM5_KVNO)) {
532 for (i = 0; i < kdb.n_key_data; i++)
533 kdb.key_data[i].key_data_kvno = entry->kvno;
536 if (mask & KADM5_TL_DATA) {
537 krb5_tl_data *tl, *tl2;
539 * Replace kdb.tl_data with what was passed in. The
540 * KRB5_TL_KADM_DATA will be re-added (based on adb) by
541 * kdb_put_entry, below.
543 * Note that we have to duplicate the passed in tl_data
544 * before adding it to kdb. The reason is that kdb_put_entry
545 * will add its own tl_data entries that we will need to
546 * free, but we cannot free the caller's tl_data (an
547 * alternative would be to scan the tl_data after put_entry
548 * and only free those entries that were not passed in).
550 while (kdb.tl_data) {
551 tl = kdb.tl_data->tl_data_next;
552 free(kdb.tl_data->tl_data_contents);
557 kdb.n_tl_data = entry->n_tl_data;
559 tl2 = entry->tl_data;
561 tl = dup_tl_data(tl2);
562 tl->tl_data_next = kdb.tl_data;
564 tl2 = tl2->tl_data_next;
568 ret = kdb_put_entry(handle, &kdb, &adb);
574 ret2 = kadm5_free_policy_ent(handle->lhandle, &opol);
575 ret = ret ? ret : ret2;
578 ret2 = kadm5_free_policy_ent(handle->lhandle, &npol);
579 ret = ret ? ret : ret2;
581 kdb_free_entry(handle, &kdb, &adb);
586 kadm5_rename_principal(void *server_handle,
587 krb5_principal source, krb5_principal target)
590 osa_princ_ent_rec adb;
592 kadm5_server_handle_t handle = server_handle;
594 CHECK_HANDLE(server_handle);
596 if (source == NULL || target == NULL)
599 if ((ret = kdb_get_entry(handle, target, &kdb, &adb)) == 0) {
600 kdb_free_entry(handle, &kdb, &adb);
604 if ((ret = kdb_get_entry(handle, source, &kdb, &adb)))
607 /* this is kinda gross, but unavoidable */
609 for (i=0; i<kdb.n_key_data; i++) {
610 if ((kdb.key_data[i].key_data_ver == 1) ||
611 (kdb.key_data[i].key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL)) {
612 ret = KADM5_NO_RENAME_SALT;
617 krb5_free_principal(handle->context, kdb.princ);
618 ret = krb5_copy_principal(handle->context, target, &kdb.princ);
620 kdb.princ = NULL; /* so freeing the dbe doesn't lose */
624 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
627 ret = kdb_delete_entry(handle, source);
630 kdb_free_entry(handle, &kdb, &adb);
635 kadm5_get_principal(void *server_handle, krb5_principal principal,
636 kadm5_principal_ent_t entry,
640 osa_princ_ent_rec adb;
641 osa_adb_ret_t ret = 0;
644 kadm5_server_handle_t handle = server_handle;
645 kadm5_principal_ent_rec entry_local, *entry_orig;
647 CHECK_HANDLE(server_handle);
650 * In version 1, all the defined fields are always returned.
651 * entry is a pointer to a kadm5_principal_ent_t_v1 that should be
652 * filled with allocated memory.
654 if (handle->api_version == KADM5_API_VERSION_1) {
655 mask = KADM5_PRINCIPAL_NORMAL_MASK;
657 entry = &entry_local;
662 memset((char *) entry, 0, sizeof(*entry));
664 if (principal == NULL)
667 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
670 if ((mask & KADM5_POLICY) &&
671 adb.policy && (adb.aux_attributes & KADM5_POLICY)) {
672 if ((entry->policy = (char *) malloc(strlen(adb.policy) + 1)) == NULL) {
676 strcpy(entry->policy, adb.policy);
679 if (mask & KADM5_AUX_ATTRIBUTES)
680 entry->aux_attributes = adb.aux_attributes;
682 if ((mask & KADM5_PRINCIPAL) &&
683 (ret = krb5_copy_principal(handle->context, principal,
684 &entry->principal))) {
688 if (mask & KADM5_PRINC_EXPIRE_TIME)
689 entry->princ_expire_time = kdb.expiration;
691 if ((mask & KADM5_LAST_PWD_CHANGE) &&
692 (ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb,
693 &(entry->last_pwd_change)))) {
697 if (mask & KADM5_PW_EXPIRATION)
698 entry->pw_expiration = kdb.pw_expiration;
699 if (mask & KADM5_MAX_LIFE)
700 entry->max_life = kdb.max_life;
702 /* this is a little non-sensical because the function returns two */
703 /* values that must be checked separately against the mask */
704 if ((mask & KADM5_MOD_NAME) || (mask & KADM5_MOD_TIME)) {
705 ret = krb5_dbe_lookup_mod_princ_data(handle->context, &kdb,
712 if (! (mask & KADM5_MOD_TIME))
714 if (! (mask & KADM5_MOD_NAME)) {
715 krb5_free_principal(handle->context, entry->principal);
716 entry->principal = NULL;
720 if (mask & KADM5_ATTRIBUTES)
721 entry->attributes = kdb.attributes;
723 if (mask & KADM5_KVNO)
724 for (entry->kvno = 0, i=0; i<kdb.n_key_data; i++)
725 if (kdb.key_data[i].key_data_kvno > entry->kvno)
726 entry->kvno = kdb.key_data[i].key_data_kvno;
728 if (handle->api_version == KADM5_API_VERSION_2)
731 /* XXX I'll be damned if I know how to deal with this one --marc */
736 * The new fields that only exist in version 2 start here
738 if (handle->api_version == KADM5_API_VERSION_2) {
739 if (mask & KADM5_MAX_RLIFE)
740 entry->max_renewable_life = kdb.max_renewable_life;
741 if (mask & KADM5_LAST_SUCCESS)
742 entry->last_success = kdb.last_success;
743 if (mask & KADM5_LAST_FAILED)
744 entry->last_failed = kdb.last_failed;
745 if (mask & KADM5_FAIL_AUTH_COUNT)
746 entry->fail_auth_count = kdb.fail_auth_count;
747 if (mask & KADM5_TL_DATA) {
748 krb5_tl_data *tl, *tl2;
750 entry->tl_data = NULL;
754 if (tl->tl_data_type > 255) {
755 if ((tl2 = dup_tl_data(tl)) == NULL) {
759 tl2->tl_data_next = entry->tl_data;
760 entry->tl_data = tl2;
764 tl = tl->tl_data_next;
767 if (mask & KADM5_KEY_DATA) {
768 entry->n_key_data = kdb.n_key_data;
769 if(entry->n_key_data) {
770 entry->key_data = (krb5_key_data *)
771 malloc(entry->n_key_data*sizeof(krb5_key_data));
772 if (entry->key_data == NULL) {
777 entry->key_data = NULL;
779 for (i = 0; i < entry->n_key_data; i++)
780 ret = krb5_copy_key_data_contents(handle->context,
782 &entry->key_data[i]);
789 * If KADM5_API_VERSION_1, we return an allocated structure, and
790 * we need to convert the new structure back into the format the
791 * caller is expecting.
793 if (handle->api_version == KADM5_API_VERSION_1) {
794 kadm5_principal_ent_t_v1 newv1;
796 newv1 = ((kadm5_principal_ent_t_v1) calloc(1, sizeof(*newv1)));
802 newv1->principal = entry->principal;
803 newv1->princ_expire_time = entry->princ_expire_time;
804 newv1->last_pwd_change = entry->last_pwd_change;
805 newv1->pw_expiration = entry->pw_expiration;
806 newv1->max_life = entry->max_life;
807 newv1->mod_name = entry->mod_name;
808 newv1->mod_date = entry->mod_date;
809 newv1->attributes = entry->attributes;
810 newv1->kvno = entry->kvno;
811 newv1->mkvno = entry->mkvno;
812 newv1->policy = entry->policy;
813 newv1->aux_attributes = entry->aux_attributes;
815 *((kadm5_principal_ent_t_v1 *) entry_orig) = newv1;
821 if (ret && entry->principal)
822 krb5_free_principal(handle->context, entry->principal);
823 kdb_free_entry(handle, &kdb, &adb);
829 * Function: check_pw_reuse
831 * Purpose: Check if a key appears in a list of keys, in order to
832 * enforce password history.
836 * context (r) the krb5 context
837 * hist_keyblock (r) the key that hist_key_data is
839 * n_new_key_data (r) length of new_key_data
840 * new_key_data (r) keys to check against
841 * pw_hist_data, encrypted in hist_keyblock
842 * n_pw_hist_data (r) length of pw_hist_data
843 * pw_hist_data (r) passwords to check new_key_data against
846 * For each new_key in new_key_data:
847 * decrypt new_key with the master_keyblock
848 * for each password in pw_hist_data:
849 * for each hist_key in password:
850 * decrypt hist_key with hist_keyblock
851 * compare the new_key and hist_key
853 * Returns krb5 errors, KADM5_PASS_RESUSE if a key in
854 * new_key_data is the same as a key in pw_hist_data, or 0.
857 check_pw_reuse(krb5_context context,
858 krb5_keyblock *hist_keyblock,
859 int n_new_key_data, krb5_key_data *new_key_data,
860 unsigned int n_pw_hist_data, osa_pw_hist_ent *pw_hist_data)
863 krb5_keyblock newkey, histkey;
866 for (x = 0; x < n_new_key_data; x++) {
867 ret = krb5_dbekd_decrypt_key_data(context,
873 for (y = 0; y < n_pw_hist_data; y++) {
874 for (z = 0; z < pw_hist_data[y].n_key_data; z++) {
875 ret = krb5_dbekd_decrypt_key_data(context,
877 &pw_hist_data[y].key_data[z],
882 if ((newkey.length == histkey.length) &&
883 (newkey.enctype == histkey.enctype) &&
884 (memcmp(newkey.contents, histkey.contents,
885 histkey.length) == 0)) {
886 krb5_free_keyblock_contents(context, &histkey);
887 krb5_free_keyblock_contents(context, &newkey);
889 return(KADM5_PASS_REUSE);
891 krb5_free_keyblock_contents(context, &histkey);
894 krb5_free_keyblock_contents(context, &newkey);
901 * Function: create_history_entry
903 * Purpose: Creates a password history entry from an array of
908 * context (r) krb5_context to use
909 * n_key_data (r) number of elements in key_data
910 * key_data (r) keys to add to the history entry
911 * hist (w) history entry to fill in
915 * hist->key_data is allocated to store n_key_data key_datas. Each
916 * element of key_data is decrypted with master_keyblock, re-encrypted
917 * in hist_key, and added to hist->key_data. hist->n_key_data is
921 int create_history_entry(krb5_context context, int n_key_data,
922 krb5_key_data *key_data, osa_pw_hist_ent *hist)
928 hist->key_data = (krb5_key_data*)malloc(n_key_data*sizeof(krb5_key_data));
929 if (hist->key_data == NULL)
931 memset(hist->key_data, 0, n_key_data*sizeof(krb5_key_data));
933 for (i = 0; i < n_key_data; i++) {
934 ret = krb5_dbekd_decrypt_key_data(context,
941 ret = krb5_dbekd_encrypt_key_data(context, &hist_key,
943 key_data[i].key_data_kvno,
948 krb5_free_keyblock_contents(context, &key);
949 /* krb5_free_keysalt(context, &salt); */
952 hist->n_key_data = n_key_data;
957 void free_history_entry(krb5_context context, osa_pw_hist_ent *hist)
961 for (i = 0; i < hist->n_key_data; i++)
962 krb5_free_key_data_contents(context, &hist->key_data[i]);
963 free(hist->key_data);
967 * Function: add_to_history
969 * Purpose: Adds a password to a principal's password history.
973 * context (r) krb5_context to use
974 * adb (r/w) admin principal entry to add keys to
975 * pol (r) adb's policy
976 * pw (r) keys for the password to add to adb's key history
980 * add_to_history adds a single password to adb's password history.
981 * pw contains n_key_data keys in its key_data, in storage should be
982 * allocated but not freed by the caller (XXX blech!).
984 * This function maintains adb->old_keys as a circular queue. It
985 * starts empty, and grows each time this function is called until it
986 * is pol->pw_history_num items long. adb->old_key_len holds the
987 * number of allocated entries in the array, and must therefore be [0,
988 * pol->pw_history_num). adb->old_key_next is the index into the
989 * array where the next element should be written, and must be [0,
992 #define KADM_MOD(x) (x + adb->old_key_next) % adb->old_key_len
993 static kadm5_ret_t add_to_history(krb5_context context,
995 kadm5_policy_ent_t pol,
998 osa_pw_hist_ent *histp;
1001 /* A history of 1 means just check the current password */
1002 if (pol->pw_history_num == 1)
1005 /* resize the adb->old_keys array if necessary */
1006 if (adb->old_key_len < pol->pw_history_num-1) {
1007 if (adb->old_keys == NULL) {
1008 adb->old_keys = (osa_pw_hist_ent *)
1009 malloc((adb->old_key_len + 1) * sizeof (osa_pw_hist_ent));
1011 adb->old_keys = (osa_pw_hist_ent *)
1012 realloc(adb->old_keys,
1013 (adb->old_key_len + 1) * sizeof (osa_pw_hist_ent));
1015 if (adb->old_keys == NULL)
1018 memset(&adb->old_keys[adb->old_key_len],0,sizeof(osa_pw_hist_ent));
1020 } else if (adb->old_key_len > pol->pw_history_num-1) {
1022 * The policy must have changed! Shrink the array.
1023 * Can't simply realloc() down, since it might be wrapped.
1024 * To understand the arithmetic below, note that we are
1025 * copying into new positions 0 .. N-1 from old positions
1026 * old_key_next-N .. old_key_next-1, modulo old_key_len,
1027 * where N = pw_history_num - 1 is the length of the
1028 * shortened list. Matt Crawford, FNAL
1031 histp = (osa_pw_hist_ent *)
1032 malloc((pol->pw_history_num - 1) * sizeof (osa_pw_hist_ent));
1034 for (i = 0; i < pol->pw_history_num - 1; i++) {
1035 /* We need the number we use the modulus operator on to be
1036 positive, so after subtracting pol->pw_history_num-1, we
1037 add back adb->old_key_len. */
1038 j = KADM_MOD(i - (pol->pw_history_num - 1) + adb->old_key_len);
1039 histp[i] = adb->old_keys[j];
1041 /* Now free the ones we don't keep (the oldest ones) */
1042 for (i = 0; i < adb->old_key_len - (pol->pw_history_num - 1); i++)
1043 for (j = 0; j < adb->old_keys[KADM_MOD(i)].n_key_data; j++)
1044 krb5_free_key_data_contents(context,
1045 &adb->old_keys[KADM_MOD(i)].key_data[j]);
1046 free((void *)adb->old_keys);
1047 adb->old_keys = histp;
1048 adb->old_key_len = pol->pw_history_num - 1;
1049 adb->old_key_next = 0;
1055 /* free the old pw history entry if it contains data */
1056 histp = &adb->old_keys[adb->old_key_next];
1057 for (i = 0; i < histp->n_key_data; i++)
1058 krb5_free_key_data_contents(context, &histp->key_data[i]);
1060 /* store the new entry */
1061 adb->old_keys[adb->old_key_next] = *pw;
1063 /* update the next pointer */
1064 if (++adb->old_key_next == pol->pw_history_num-1)
1065 adb->old_key_next = 0;
1071 #ifdef USE_PASSWORD_SERVER
1073 /* FIXME: don't use global variable for this */
1074 krb5_boolean use_password_server = 0;
1077 kadm5_use_password_server (void)
1079 return use_password_server;
1083 kadm5_set_use_password_server (void)
1085 use_password_server = 1;
1089 * kadm5_launch_task () runs a program (task_path) to synchronize the
1090 * Apple password server with the Kerberos database. Password server
1091 * programs can receive arguments on the command line (task_argv)
1092 * and a block of data via stdin (data_buffer). On success, they
1093 * return one of the result codes listed in success_codes.
1095 * Because a failure to communicate with the tool results in the
1096 * password server falling out of sync with the database,
1097 * kadm5_launch_task() always fails if it can't talk to the tool.
1101 kadm5_launch_task (krb5_context context,
1102 const char *task_path, char * const task_argv[],
1103 const char *data_buffer)
1105 kadm5_ret_t ret = 0;
1108 if (data_buffer != NULL) {
1109 ret = pipe (data_pipe);
1110 if (ret) { ret = errno; }
1114 pid_t pid = fork ();
1117 } else if (pid == 0) {
1120 if (data_buffer != NULL) {
1121 if (dup2 (data_pipe[0], STDIN_FILENO) == -1) {
1125 close (data_pipe[0]);
1128 close (data_pipe[1]);
1130 execv (task_path, task_argv);
1132 _exit (1); /* Fail if execv fails */
1136 if (data_buffer != NULL) {
1137 /* Write out the buffer to the child */
1138 if (krb5_net_write (context, data_pipe[1],
1139 data_buffer, strlen (data_buffer)) < 0) {
1144 close (data_buffer[0]);
1145 close (data_buffer[1]);
1150 waitpid (pid, &status, 0);
1152 /* fprintf (stderr, "Call \"%s\" returned status %d\n", argv[2],
1153 WEXITSTATUS(status)); */
1155 if (WIFEXITED (status)) {
1156 /* task finished. Check return value */
1157 if ((WEXITSTATUS (status) != 0) && (WEXITSTATUS (status) != 252)) {
1158 ret = KRB5KDC_ERR_POLICY; /* password change rejected */
1161 /* task crashed or was killed */
1162 ret = KRB5KRB_ERR_GENERIC; /* FIXME: better error */
1165 /* since the password write failed, just try and kill the child
1166 * process in order to clean up (it may already be gone). */
1167 kill (pid, SIGKILL);
1178 kadm5_chpass_principal(void *server_handle,
1179 krb5_principal principal, char *password)
1182 kadm5_chpass_principal_3(server_handle, principal, FALSE,
1187 kadm5_chpass_principal_3(void *server_handle,
1188 krb5_principal principal, krb5_boolean keepold,
1189 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1193 kadm5_policy_ent_rec pol;
1194 osa_princ_ent_rec adb;
1195 krb5_db_entry kdb, kdb_save;
1196 int ret, ret2, last_pwd, hist_added;
1198 kadm5_server_handle_t handle = server_handle;
1199 osa_pw_hist_ent hist;
1201 CHECK_HANDLE(server_handle);
1204 memset(&hist, 0, sizeof(hist));
1206 if (principal == NULL || password == NULL)
1208 if ((krb5_principal_compare(handle->context,
1209 principal, hist_princ)) == TRUE)
1210 return KADM5_PROTECT_PRINCIPAL;
1212 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1215 /* we are going to need the current keys after the new keys are set */
1216 if ((ret = kdb_get_entry(handle, principal, &kdb_save, NULL))) {
1217 kdb_free_entry(handle, &kdb, &adb);
1221 if ((adb.aux_attributes & KADM5_POLICY)) {
1222 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &pol)))
1227 if ((ret = passwd_check(handle, password, adb.aux_attributes &
1228 KADM5_POLICY, &pol, principal)))
1231 ret = krb5_dbe_cpw(handle->context, &master_keyblock,
1232 n_ks_tuple?ks_tuple:handle->params.keysalts,
1233 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
1234 password, 0 /* increment kvno */,
1239 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1241 ret = krb5_timeofday(handle->context, &now);
1245 if ((adb.aux_attributes & KADM5_POLICY)) {
1246 /* the policy was loaded before */
1248 ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1255 * The spec says this check is overridden if the caller has
1256 * modify privilege. The admin server therefore makes this
1257 * check itself (in chpass_principal_wrapper, misc.c). A
1258 * local caller implicitly has all authorization bits.
1260 if ((now - last_pwd) < pol.pw_min_life &&
1261 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1262 ret = KADM5_PASS_TOOSOON;
1267 ret = create_history_entry(handle->context,
1268 kdb_save.n_key_data,
1269 kdb_save.key_data, &hist);
1273 ret = check_pw_reuse(handle->context, &hist_key,
1274 kdb.n_key_data, kdb.key_data,
1279 if (pol.pw_history_num > 1) {
1280 if (adb.admin_history_kvno != hist_kvno) {
1281 ret = KADM5_BAD_HIST_KEY;
1285 ret = check_pw_reuse(handle->context, &hist_key,
1286 kdb.n_key_data, kdb.key_data,
1287 adb.old_key_len, adb.old_keys);
1291 ret = add_to_history(handle->context, &adb, &pol, &hist);
1297 if (pol.pw_max_life)
1298 kdb.pw_expiration = now + pol.pw_max_life;
1300 kdb.pw_expiration = 0;
1302 kdb.pw_expiration = 0;
1305 #ifdef USE_PASSWORD_SERVER
1306 if (kadm5_use_password_server () &&
1307 (krb5_princ_size (handle->context, principal) == 1)) {
1308 krb5_data *princ = krb5_princ_component (handle->context, principal, 0);
1309 const char *path = "/usr/sbin/mkpassdb";
1310 char *argv[] = { "mkpassdb", "-setpassword", NULL, NULL };
1311 char *pstring = NULL;
1313 int pwlen = strlen (password);
1315 if (pwlen > 254) pwlen = 254;
1316 strncpy (pwbuf, password, pwlen);
1317 pwbuf[pwlen] = '\n';
1318 pwbuf[pwlen + 1] = '\0';
1321 pstring = malloc ((princ->length + 1) * sizeof (char));
1322 if (pstring == NULL) { ret = errno; }
1326 memcpy (pstring, princ->data, princ->length);
1327 pstring [princ->length] = '\0';
1330 ret = kadm5_launch_task (handle->context, path, argv, pwbuf);
1333 if (pstring != NULL)
1341 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
1345 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1350 if (!hist_added && hist.key_data)
1351 free_history_entry(handle->context, &hist);
1352 kdb_free_entry(handle, &kdb, &adb);
1353 kdb_free_entry(handle, &kdb_save, NULL);
1354 krb5_dbe_free_contents(handle->context, &kdb);
1356 if (have_pol && (ret2 = kadm5_free_policy_ent(handle->lhandle, &pol))
1364 kadm5_randkey_principal(void *server_handle,
1365 krb5_principal principal,
1366 krb5_keyblock **keyblocks,
1370 kadm5_randkey_principal_3(server_handle, principal,
1375 kadm5_randkey_principal_3(void *server_handle,
1376 krb5_principal principal,
1377 krb5_boolean keepold,
1378 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1379 krb5_keyblock **keyblocks,
1383 osa_princ_ent_rec adb;
1385 kadm5_policy_ent_rec pol;
1386 krb5_key_data *key_data;
1387 int ret, last_pwd, have_pol = 0;
1388 kadm5_server_handle_t handle = server_handle;
1393 CHECK_HANDLE(server_handle);
1395 if (principal == NULL)
1397 if (hist_princ && /* this will be NULL when initializing the databse */
1398 ((krb5_principal_compare(handle->context,
1399 principal, hist_princ)) == TRUE))
1400 return KADM5_PROTECT_PRINCIPAL;
1402 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1405 ret = krb5_dbe_crk(handle->context, &master_keyblock,
1406 n_ks_tuple?ks_tuple:handle->params.keysalts,
1407 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
1413 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1415 ret = krb5_timeofday(handle->context, &now);
1419 if ((adb.aux_attributes & KADM5_POLICY)) {
1420 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1425 ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1432 * The spec says this check is overridden if the caller has
1433 * modify privilege. The admin server therefore makes this
1434 * check itself (in chpass_principal_wrapper, misc.c). A
1435 * local caller implicitly has all authorization bits.
1437 if((now - last_pwd) < pol.pw_min_life &&
1438 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1439 ret = KADM5_PASS_TOOSOON;
1444 if(pol.pw_history_num > 1) {
1445 if(adb.admin_history_kvno != hist_kvno) {
1446 ret = KADM5_BAD_HIST_KEY;
1450 ret = check_pw_reuse(handle->context, &hist_key,
1451 kdb.n_key_data, kdb.key_data,
1452 adb.old_key_len, adb.old_keys);
1456 if (pol.pw_max_life)
1457 kdb.pw_expiration = now + pol.pw_max_life;
1459 kdb.pw_expiration = 0;
1461 kdb.pw_expiration = 0;
1464 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
1469 if (handle->api_version == KADM5_API_VERSION_1) {
1470 /* Version 1 clients will expect to see a DES_CRC enctype. */
1471 ret = krb5_dbe_find_enctype(handle->context, &kdb,
1472 ENCTYPE_DES_CBC_CRC,
1477 ret = decrypt_key_data(handle->context, 1, key_data,
1482 ret = decrypt_key_data(handle->context,
1483 kdb.n_key_data, kdb.key_data,
1490 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1495 kdb_free_entry(handle, &kdb, &adb);
1497 kadm5_free_policy_ent(handle->lhandle, &pol);
1503 * kadm5_setv4key_principal:
1505 * Set only ONE key of the principal, removing all others. This key
1506 * must have the DES_CBC_CRC enctype and is entered as having the
1507 * krb4 salttype. This is to enable things like kadmind4 to work.
1510 kadm5_setv4key_principal(void *server_handle,
1511 krb5_principal principal,
1512 krb5_keyblock *keyblock)
1515 osa_princ_ent_rec adb;
1517 kadm5_policy_ent_rec pol;
1518 krb5_keysalt keysalt;
1519 int i, kvno, ret, have_pol = 0;
1523 kadm5_server_handle_t handle = server_handle;
1525 CHECK_HANDLE(server_handle);
1527 if (principal == NULL || keyblock == NULL)
1529 if (hist_princ && /* this will be NULL when initializing the databse */
1530 ((krb5_principal_compare(handle->context,
1531 principal, hist_princ)) == TRUE))
1532 return KADM5_PROTECT_PRINCIPAL;
1534 if (keyblock->enctype != ENCTYPE_DES_CBC_CRC)
1535 return KADM5_SETV4KEY_INVAL_ENCTYPE;
1537 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1540 for (kvno = 0, i=0; i<kdb.n_key_data; i++)
1541 if (kdb.key_data[i].key_data_kvno > kvno)
1542 kvno = kdb.key_data[i].key_data_kvno;
1544 if (kdb.key_data != NULL)
1545 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
1547 kdb.key_data = (krb5_key_data*)malloc(sizeof(krb5_key_data));
1548 if (kdb.key_data == NULL)
1550 memset(kdb.key_data, 0, sizeof(krb5_key_data));
1552 keysalt.type = KRB5_KDB_SALTTYPE_V4;
1553 /* XXX data.magic? */
1554 keysalt.data.length = 0;
1555 keysalt.data.data = NULL;
1557 ret = krb5_dbekd_encrypt_key_data(handle->context, &master_keyblock,
1558 keyblock, &keysalt, kvno + 1,
1564 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1566 ret = krb5_timeofday(handle->context, &now);
1570 if ((adb.aux_attributes & KADM5_POLICY)) {
1571 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1578 * The spec says this check is overridden if the caller has
1579 * modify privilege. The admin server therefore makes this
1580 * check itself (in chpass_principal_wrapper, misc.c). A
1581 * local caller implicitly has all authorization bits.
1583 if (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1586 if((now - last_pwd) < pol.pw_min_life &&
1587 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1588 ret = KADM5_PASS_TOOSOON;
1594 * Should we be checking/updating pw history here?
1596 if(pol.pw_history_num > 1) {
1597 if(adb.admin_history_kvno != hist_kvno) {
1598 ret = KADM5_BAD_HIST_KEY;
1602 if (ret = check_pw_reuse(handle->context,
1604 kdb.n_key_data, kdb.key_data,
1605 adb.old_key_len, adb.old_keys))
1610 if (pol.pw_max_life)
1611 kdb.pw_expiration = now + pol.pw_max_life;
1613 kdb.pw_expiration = 0;
1615 kdb.pw_expiration = 0;
1618 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
1622 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1627 kdb_free_entry(handle, &kdb, &adb);
1629 kadm5_free_policy_ent(handle->lhandle, &pol);
1635 kadm5_setkey_principal(void *server_handle,
1636 krb5_principal principal,
1637 krb5_keyblock *keyblocks,
1641 kadm5_setkey_principal_3(server_handle, principal,
1647 kadm5_setkey_principal_3(void *server_handle,
1648 krb5_principal principal,
1649 krb5_boolean keepold,
1650 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1651 krb5_keyblock *keyblocks,
1655 osa_princ_ent_rec adb;
1657 kadm5_policy_ent_rec pol;
1658 krb5_key_data *old_key_data;
1660 int i, j, kvno, ret, have_pol = 0;
1664 kadm5_server_handle_t handle = server_handle;
1665 krb5_boolean similar;
1666 krb5_keysalt keysalt;
1668 CHECK_HANDLE(server_handle);
1670 if (principal == NULL || keyblocks == NULL)
1672 if (hist_princ && /* this will be NULL when initializing the databse */
1673 ((krb5_principal_compare(handle->context,
1674 principal, hist_princ)) == TRUE))
1675 return KADM5_PROTECT_PRINCIPAL;
1677 for (i = 0; i < n_keys; i++) {
1678 for (j = i+1; j < n_keys; j++) {
1679 if ((ret = krb5_c_enctype_compare(handle->context,
1680 keyblocks[i].enctype,
1681 keyblocks[j].enctype,
1686 if (ks_tuple[i].ks_salttype == ks_tuple[j].ks_salttype)
1687 return KADM5_SETKEY_DUP_ENCTYPES;
1689 return KADM5_SETKEY_DUP_ENCTYPES;
1694 if (n_ks_tuple && n_ks_tuple != n_keys)
1695 return KADM5_SETKEY3_ETYPE_MISMATCH;
1697 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1700 for (kvno = 0, i=0; i<kdb.n_key_data; i++)
1701 if (kdb.key_data[i].key_data_kvno > kvno)
1702 kvno = kdb.key_data[i].key_data_kvno;
1705 old_key_data = kdb.key_data;
1706 n_old_keys = kdb.n_key_data;
1708 if (kdb.key_data != NULL)
1709 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
1711 old_key_data = NULL;
1714 kdb.key_data = (krb5_key_data*)malloc((n_keys+n_old_keys)
1715 *sizeof(krb5_key_data));
1716 if (kdb.key_data == NULL)
1718 memset(kdb.key_data, 0, (n_keys+n_old_keys)*sizeof(krb5_key_data));
1721 for (i = 0; i < n_keys; i++) {
1723 keysalt.type = ks_tuple[i].ks_salttype;
1724 keysalt.data.length = 0;
1725 keysalt.data.data = NULL;
1726 if (ks_tuple[i].ks_enctype != keyblocks[i].enctype) {
1727 cleanup_key_data(handle->context, kdb.n_key_data,
1729 return KADM5_SETKEY3_ETYPE_MISMATCH;
1732 ret = krb5_dbekd_encrypt_key_data(handle->context,
1735 n_ks_tuple ? &keysalt : NULL,
1739 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
1745 /* copy old key data if necessary */
1746 for (i = 0; i < n_old_keys; i++) {
1747 kdb.key_data[i+n_keys] = old_key_data[i];
1748 memset(&old_key_data[i], 0, sizeof (krb5_key_data));
1751 /* assert(kdb.n_key_data == n_keys + n_old_keys) */
1752 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1754 if ((ret = krb5_timeofday(handle->context, &now)))
1757 if ((adb.aux_attributes & KADM5_POLICY)) {
1758 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1765 * The spec says this check is overridden if the caller has
1766 * modify privilege. The admin server therefore makes this
1767 * check itself (in chpass_principal_wrapper, misc.c). A
1768 * local caller implicitly has all authorization bits.
1770 if (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1773 if((now - last_pwd) < pol.pw_min_life &&
1774 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1775 ret = KADM5_PASS_TOOSOON;
1781 * Should we be checking/updating pw history here?
1783 if(pol.pw_history_num > 1) {
1784 if(adb.admin_history_kvno != hist_kvno) {
1785 ret = KADM5_BAD_HIST_KEY;
1789 if (ret = check_pw_reuse(handle->context,
1791 kdb.n_key_data, kdb.key_data,
1792 adb.old_key_len, adb.old_keys))
1797 if (pol.pw_max_life)
1798 kdb.pw_expiration = now + pol.pw_max_life;
1800 kdb.pw_expiration = 0;
1802 kdb.pw_expiration = 0;
1805 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now)))
1808 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1813 kdb_free_entry(handle, &kdb, &adb);
1815 kadm5_free_policy_ent(handle->lhandle, &pol);
1821 * Allocate an array of n_key_data krb5_keyblocks, fill in each
1822 * element with the results of decrypting the nth key in key_data with
1823 * master_keyblock, and if n_keys is not NULL fill it in with the
1824 * number of keys decrypted.
1826 static int decrypt_key_data(krb5_context context,
1827 int n_key_data, krb5_key_data *key_data,
1828 krb5_keyblock **keyblocks, int *n_keys)
1830 krb5_keyblock *keys;
1833 keys = (krb5_keyblock *) malloc(n_key_data*sizeof(krb5_keyblock));
1836 memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock));
1838 for (i = 0; i < n_key_data; i++) {
1839 ret = krb5_dbekd_decrypt_key_data(context, &master_keyblock,
1844 memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock));
1852 *n_keys = n_key_data;
1858 * Function: kadm5_decrypt_key
1860 * Purpose: Retrieves and decrypts a principal key.
1864 * server_handle (r) kadm5 handle
1865 * entry (r) principal retrieved with kadm5_get_principal
1866 * ktype (r) enctype to search for, or -1 to ignore
1867 * stype (r) salt type to search for, or -1 to ignore
1868 * kvno (r) kvno to search for, -1 for max, 0 for max
1869 * only if it also matches ktype and stype
1870 * keyblock (w) keyblock to fill in
1871 * keysalt (w) keysalt to fill in, or NULL
1872 * kvnop (w) kvno to fill in, or NULL
1874 * Effects: Searches the key_data array of entry, which must have been
1875 * retrived with kadm5_get_principal with the KADM5_KEY_DATA mask, to
1876 * find a key with a specified enctype, salt type, and kvno in a
1877 * principal entry. If not found, return ENOENT. Otherwise, decrypt
1878 * it with the master key, and return the key in keyblock, the salt
1879 * in salttype, and the key version number in kvno.
1881 * If ktype or stype is -1, it is ignored for the search. If kvno is
1882 * -1, ktype and stype are ignored and the key with the max kvno is
1883 * returned. If kvno is 0, only the key with the max kvno is returned
1884 * and only if it matches the ktype and stype; otherwise, ENOENT is
1887 kadm5_ret_t kadm5_decrypt_key(void *server_handle,
1888 kadm5_principal_ent_t entry, krb5_int32
1889 ktype, krb5_int32 stype, krb5_int32
1890 kvno, krb5_keyblock *keyblock,
1891 krb5_keysalt *keysalt, int *kvnop)
1893 kadm5_server_handle_t handle = server_handle;
1894 krb5_db_entry dbent;
1895 krb5_key_data *key_data;
1898 CHECK_HANDLE(server_handle);
1900 if (entry->n_key_data == 0 || entry->key_data == NULL)
1903 /* find_enctype only uses these two fields */
1904 dbent.n_key_data = entry->n_key_data;
1905 dbent.key_data = entry->key_data;
1906 if ((ret = krb5_dbe_find_enctype(handle->context, &dbent, ktype,
1907 stype, kvno, &key_data)))
1910 if ((ret = krb5_dbekd_decrypt_key_data(handle->context,
1911 &master_keyblock, key_data,
1912 keyblock, keysalt)))
1916 * Coerce the enctype of the output keyblock in case we got an
1917 * inexact match on the enctype; this behavior will go away when
1918 * the key storage architecture gets redesigned for 1.3.
1920 keyblock->enctype = ktype;
1923 *kvnop = key_data->key_data_kvno;