1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
8 #if !defined(lint) && !defined(__CODECENTER__)
9 static char *rcsid = "$Header$";
12 #include <sys/types.h>
15 #include <kadm5/admin.h>
19 #include "server_internal.h"
22 #ifdef USE_PASSWORD_SERVER
29 #include <valgrind/memcheck.h>
31 #define VALGRIND_CHECK_DEFINED(LVALUE) ((void)0)
34 extern krb5_principal master_princ;
35 extern krb5_principal hist_princ;
36 extern krb5_keyblock master_keyblock;
37 extern krb5_keylist_node *master_keylist;
38 extern krb5_actkvno_node *active_mkey_list;
39 extern krb5_db_entry master_db;
41 static int decrypt_key_data(krb5_context context, krb5_keyblock *mkey,
42 int n_key_data, krb5_key_data *key_data,
43 krb5_keyblock **keyblocks, int *n_keys);
45 static krb5_error_code
46 kadm5_copy_principal(krb5_context context, krb5_const_principal inprinc, krb5_principal *outprinc)
48 register krb5_principal tempprinc;
49 register int i, nelems;
51 tempprinc = (krb5_principal)krb5_db_alloc(context, NULL, sizeof(krb5_principal_data));
56 VALGRIND_CHECK_DEFINED(*inprinc);
57 *tempprinc = *inprinc;
59 nelems = (int) krb5_princ_size(context, inprinc);
60 tempprinc->data = krb5_db_alloc(context, NULL, nelems * sizeof(krb5_data));
61 if (tempprinc->data == 0) {
62 krb5_db_free(context, (char *)tempprinc);
66 for (i = 0; i < nelems; i++) {
67 unsigned int len = krb5_princ_component(context, inprinc, i)->length;
68 krb5_princ_component(context, tempprinc, i)->length = len;
69 if (((krb5_princ_component(context, tempprinc, i)->data =
70 krb5_db_alloc(context, NULL, len)) == 0) && len) {
72 krb5_db_free(context, krb5_princ_component(context, tempprinc, i)->data);
73 krb5_db_free (context, tempprinc->data);
74 krb5_db_free (context, tempprinc);
78 memcpy(krb5_princ_component(context, tempprinc, i)->data,
79 krb5_princ_component(context, inprinc, i)->data, len);
80 krb5_princ_component(context, tempprinc, i)->magic = KV5M_DATA;
83 tempprinc->realm.data =
84 krb5_db_alloc(context, NULL, tempprinc->realm.length = inprinc->realm.length);
85 if (!tempprinc->realm.data && tempprinc->realm.length) {
86 for (i = 0; i < nelems; i++)
87 krb5_db_free(context, krb5_princ_component(context, tempprinc, i)->data);
88 krb5_db_free(context, tempprinc->data);
89 krb5_db_free(context, tempprinc);
92 if (tempprinc->realm.length)
93 memcpy(tempprinc->realm.data, inprinc->realm.data,
94 inprinc->realm.length);
96 *outprinc = tempprinc;
101 kadm5_free_principal(krb5_context context, krb5_principal val)
103 register krb5_int32 i;
109 i = krb5_princ_size(context, val);
111 krb5_db_free(context, krb5_princ_component(context, val, i)->data);
112 krb5_db_free(context, val->data);
115 krb5_db_free(context, val->realm.data);
116 krb5_db_free(context, val);
120 * XXX Functions that ought to be in libkrb5.a, but aren't.
122 kadm5_ret_t krb5_copy_key_data_contents(context, from, to)
123 krb5_context context;
124 krb5_key_data *from, *to;
130 idx = (from->key_data_ver == 1 ? 1 : 2);
132 for (i = 0; i < idx; i++) {
133 if ( from->key_data_length[i] ) {
134 to->key_data_contents[i] = malloc(from->key_data_length[i]);
135 if (to->key_data_contents[i] == NULL) {
136 for (i = 0; i < idx; i++) {
137 if (to->key_data_contents[i]) {
138 memset(to->key_data_contents[i], 0,
139 to->key_data_length[i]);
140 free(to->key_data_contents[i]);
145 memcpy(to->key_data_contents[i], from->key_data_contents[i],
146 from->key_data_length[i]);
152 static krb5_tl_data *dup_tl_data(krb5_tl_data *tl)
156 n = (krb5_tl_data *) malloc(sizeof(krb5_tl_data));
159 n->tl_data_contents = malloc(tl->tl_data_length);
160 if (n->tl_data_contents == NULL) {
164 memcpy(n->tl_data_contents, tl->tl_data_contents, tl->tl_data_length);
165 n->tl_data_type = tl->tl_data_type;
166 n->tl_data_length = tl->tl_data_length;
167 n->tl_data_next = NULL;
171 /* This is in lib/kdb/kdb_cpw.c, but is static */
172 static void cleanup_key_data(context, count, data)
173 krb5_context context;
175 krb5_key_data * data;
179 for (i = 0; i < count; i++)
180 for (j = 0; j < data[i].key_data_ver; j++)
181 if (data[i].key_data_length[j])
182 krb5_db_free(context, data[i].key_data_contents[j]);
183 krb5_db_free(context, data);
187 * Set *passptr to NULL if the request looks like the first part of a krb5 1.6
188 * addprinc -randkey operation. The krb5 1.6 dummy password for these requests
189 * was invalid UTF-8, which runs afoul of the arcfour string-to-key.
192 check_1_6_dummy(kadm5_principal_ent_t entry, long mask,
193 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, char **passptr)
196 char *password = *passptr;
198 /* Old-style randkey operations disallowed tickets to start. */
199 if (!(mask & KADM5_ATTRIBUTES) ||
200 !(entry->attributes & KRB5_KDB_DISALLOW_ALL_TIX))
203 /* The 1.6 dummy password was the octets 1..255. */
204 for (i = 0; (unsigned char) password[i] == i + 1; i++);
205 if (password[i] != '\0' || i != 255)
208 /* This will make the caller use a random password instead. */
213 kadm5_create_principal(void *server_handle,
214 kadm5_principal_ent_t entry, long mask,
218 kadm5_create_principal_3(server_handle, entry, mask,
222 kadm5_create_principal_3(void *server_handle,
223 kadm5_principal_ent_t entry, long mask,
224 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
228 osa_princ_ent_rec adb;
229 kadm5_policy_ent_rec polent;
231 krb5_tl_data *tl_data_orig, *tl_data_tail;
233 kadm5_server_handle_t handle = server_handle;
234 krb5_keyblock *act_mkey;
237 CHECK_HANDLE(server_handle);
239 krb5_clear_error_message(handle->context);
241 check_1_6_dummy(entry, mask, n_ks_tuple, ks_tuple, &password);
244 * Argument sanity checking, and opening up the DB
246 if(!(mask & KADM5_PRINCIPAL) || (mask & KADM5_MOD_NAME) ||
247 (mask & KADM5_MOD_TIME) || (mask & KADM5_LAST_PWD_CHANGE) ||
248 (mask & KADM5_MKVNO) || (mask & KADM5_POLICY_CLR) ||
249 (mask & KADM5_AUX_ATTRIBUTES) || (mask & KADM5_KEY_DATA) ||
250 (mask & KADM5_LAST_SUCCESS) || (mask & KADM5_LAST_FAILED) ||
251 (mask & KADM5_FAIL_AUTH_COUNT))
252 return KADM5_BAD_MASK;
253 if((mask & ~ALL_PRINC_MASK))
254 return KADM5_BAD_MASK;
259 * Check to see if the principal exists
261 ret = kdb_get_entry(handle, entry->principal, &kdb, &adb);
264 case KADM5_UNK_PRINC:
267 kdb_free_entry(handle, &kdb, &adb);
273 memset(&kdb, 0, sizeof(krb5_db_entry));
274 memset(&adb, 0, sizeof(osa_princ_ent_rec));
277 * If a policy was specified, load it.
278 * If we can not find the one specified return an error
280 if ((mask & KADM5_POLICY)) {
281 if ((ret = kadm5_get_policy(handle->lhandle, entry->policy,
282 &polent)) != KADM5_OK) {
284 return KADM5_BAD_POLICY;
290 ret = passwd_check(handle, password, (mask & KADM5_POLICY),
291 &polent, entry->principal);
293 if (mask & KADM5_POLICY)
294 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
299 * Start populating the various DB fields, using the
300 * "defaults" for fields that were not specified by the
303 if ((ret = krb5_timeofday(handle->context, &now))) {
304 if (mask & KADM5_POLICY)
305 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
309 kdb.magic = KRB5_KDB_MAGIC_NUMBER;
310 kdb.len = KRB5_KDB_V1_BASE_LENGTH; /* gag me with a chainsaw */
312 if ((mask & KADM5_ATTRIBUTES))
313 kdb.attributes = entry->attributes;
315 kdb.attributes = handle->params.flags;
317 if ((mask & KADM5_MAX_LIFE))
318 kdb.max_life = entry->max_life;
320 kdb.max_life = handle->params.max_life;
322 if (mask & KADM5_MAX_RLIFE)
323 kdb.max_renewable_life = entry->max_renewable_life;
325 kdb.max_renewable_life = handle->params.max_rlife;
327 if ((mask & KADM5_PRINC_EXPIRE_TIME))
328 kdb.expiration = entry->princ_expire_time;
330 kdb.expiration = handle->params.expiration;
332 kdb.pw_expiration = 0;
333 if ((mask & KADM5_POLICY)) {
334 if(polent.pw_max_life)
335 kdb.pw_expiration = now + polent.pw_max_life;
337 kdb.pw_expiration = 0;
339 if ((mask & KADM5_PW_EXPIRATION))
340 kdb.pw_expiration = entry->pw_expiration;
342 kdb.last_success = 0;
344 kdb.fail_auth_count = 0;
346 /* this is kind of gross, but in order to free the tl data, I need
347 to free the entire kdb entry, and that will try to free the
350 if ((ret = kadm5_copy_principal(handle->context,
351 entry->principal, &(kdb.princ)))) {
352 if (mask & KADM5_POLICY)
353 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
357 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now))) {
358 krb5_db_free_principal(handle->context, &kdb, 1);
359 if (mask & KADM5_POLICY)
360 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
364 if (mask & KADM5_TL_DATA) {
365 /* splice entry->tl_data onto the front of kdb.tl_data */
366 tl_data_orig = kdb.tl_data;
367 for (tl_data_tail = entry->tl_data; tl_data_tail;
368 tl_data_tail = tl_data_tail->tl_data_next)
370 ret = krb5_dbe_update_tl_data(handle->context, &kdb, tl_data_tail);
373 krb5_db_free_principal(handle->context, &kdb, 1);
374 if (mask & KADM5_POLICY)
375 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
381 /* initialize the keys */
383 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
384 active_mkey_list, &act_kvno, &act_mkey);
386 krb5_db_free_principal(handle->context, &kdb, 1);
387 if (mask & KADM5_POLICY)
388 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
393 ret = krb5_dbe_cpw(handle->context, act_mkey,
394 n_ks_tuple?ks_tuple:handle->params.keysalts,
395 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
396 password, (mask & KADM5_KVNO)?entry->kvno:1,
399 /* Null password means create with random key (new in 1.8). */
400 ret = krb5_dbe_crk(handle->context, &master_keyblock,
401 n_ks_tuple?ks_tuple:handle->params.keysalts,
402 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
406 krb5_db_free_principal(handle->context, &kdb, 1);
407 if (mask & KADM5_POLICY)
408 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
412 /* Record the master key VNO used to encrypt this entry's keys */
413 ret = krb5_dbe_update_mkvno(handle->context, &kdb, act_kvno);
416 krb5_db_free_principal(handle->context, &kdb, 1);
417 if (mask & KADM5_POLICY)
418 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
422 /* populate the admin-server-specific fields. In the OV server,
423 this used to be in a separate database. Since there's already
424 marshalling code for the admin fields, to keep things simple,
425 I'm going to keep it, and make all the admin stuff occupy a
426 single tl_data record, */
428 adb.admin_history_kvno = INITIAL_HIST_KVNO;
429 if ((mask & KADM5_POLICY)) {
430 adb.aux_attributes = KADM5_POLICY;
432 /* this does *not* need to be strdup'ed, because adb is xdr */
433 /* encoded in osa_adb_create_princ, and not ever freed */
435 adb.policy = entry->policy;
438 /* increment the policy ref count, if any */
440 if ((mask & KADM5_POLICY)) {
441 polent.policy_refcnt++;
442 if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent,
445 krb5_db_free_principal(handle->context, &kdb, 1);
446 if (mask & KADM5_POLICY)
447 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
452 /* In all cases key and the principal data is set, let the database provider know */
453 kdb.mask = mask | KADM5_KEY_DATA | KADM5_PRINCIPAL ;
455 /* store the new db entry */
456 ret = kdb_put_entry(handle, &kdb, &adb);
458 krb5_db_free_principal(handle->context, &kdb, 1);
461 if ((mask & KADM5_POLICY)) {
462 /* decrement the policy ref count */
464 polent.policy_refcnt--;
466 * if this fails, there's nothing we can do anyway. the
467 * policy refcount wil be too high.
469 (void) kadm5_modify_policy_internal(handle->lhandle, &polent,
473 if (mask & KADM5_POLICY)
474 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
478 if (mask & KADM5_POLICY)
479 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
486 kadm5_delete_principal(void *server_handle, krb5_principal principal)
489 kadm5_policy_ent_rec polent;
491 osa_princ_ent_rec adb;
492 kadm5_server_handle_t handle = server_handle;
494 CHECK_HANDLE(server_handle);
496 krb5_clear_error_message(handle->context);
498 if (principal == NULL)
501 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
504 if ((adb.aux_attributes & KADM5_POLICY)) {
505 if ((ret = kadm5_get_policy(handle->lhandle,
506 adb.policy, &polent))
508 polent.policy_refcnt--;
509 if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent,
512 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
513 kdb_free_entry(handle, &kdb, &adb);
517 if ((ret = kadm5_free_policy_ent(handle->lhandle, &polent))) {
518 kdb_free_entry(handle, &kdb, &adb);
523 ret = kdb_delete_entry(handle, principal);
525 kdb_free_entry(handle, &kdb, &adb);
531 kadm5_modify_principal(void *server_handle,
532 kadm5_principal_ent_t entry, long mask)
535 kadm5_policy_ent_rec npol, opol;
536 int have_npol = 0, have_opol = 0;
538 krb5_tl_data *tl_data_orig;
539 osa_princ_ent_rec adb;
540 kadm5_server_handle_t handle = server_handle;
542 CHECK_HANDLE(server_handle);
544 krb5_clear_error_message(handle->context);
546 if((mask & KADM5_PRINCIPAL) || (mask & KADM5_LAST_PWD_CHANGE) ||
547 (mask & KADM5_MOD_TIME) || (mask & KADM5_MOD_NAME) ||
548 (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) ||
549 (mask & KADM5_KEY_DATA) || (mask & KADM5_LAST_SUCCESS) ||
550 (mask & KADM5_LAST_FAILED))
551 return KADM5_BAD_MASK;
552 if((mask & ~ALL_PRINC_MASK))
553 return KADM5_BAD_MASK;
554 if((mask & KADM5_POLICY) && (mask & KADM5_POLICY_CLR))
555 return KADM5_BAD_MASK;
556 if(entry == (kadm5_principal_ent_t) NULL)
558 if (mask & KADM5_TL_DATA) {
559 tl_data_orig = entry->tl_data;
560 while (tl_data_orig) {
561 if (tl_data_orig->tl_data_type < 256)
562 return KADM5_BAD_TL_TYPE;
563 tl_data_orig = tl_data_orig->tl_data_next;
567 ret = kdb_get_entry(handle, entry->principal, &kdb, &adb);
572 * This is pretty much the same as create ...
575 if ((mask & KADM5_POLICY)) {
576 /* get the new policy */
577 ret = kadm5_get_policy(handle->lhandle, entry->policy, &npol);
581 ret = KADM5_BAD_POLICY;
583 case KADM5_UNK_POLICY:
584 case KADM5_BAD_POLICY:
585 ret = KADM5_UNK_POLICY;
592 /* if we already have a policy, get it to decrement the refcnt */
593 if(adb.aux_attributes & KADM5_POLICY) {
594 /* ... but not if the old and new are the same */
595 if(strcmp(adb.policy, entry->policy)) {
596 ret = kadm5_get_policy(handle->lhandle,
600 case KADM5_BAD_POLICY:
601 case KADM5_UNK_POLICY:
605 opol.policy_refcnt--;
611 npol.policy_refcnt++;
613 } else npol.policy_refcnt++;
615 /* set us up to use the new policy */
616 adb.aux_attributes |= KADM5_POLICY;
619 adb.policy = strdup(entry->policy);
621 /* set pw_max_life based on new policy */
622 if (npol.pw_max_life) {
623 ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb,
624 &(kdb.pw_expiration));
627 kdb.pw_expiration += npol.pw_max_life;
629 kdb.pw_expiration = 0;
633 if ((mask & KADM5_POLICY_CLR) &&
634 (adb.aux_attributes & KADM5_POLICY)) {
635 ret = kadm5_get_policy(handle->lhandle, adb.policy, &opol);
638 case KADM5_BAD_POLICY:
639 case KADM5_UNK_POLICY:
648 adb.aux_attributes &= ~KADM5_POLICY;
649 kdb.pw_expiration = 0;
650 opol.policy_refcnt--;
658 if (((mask & KADM5_POLICY) || (mask & KADM5_POLICY_CLR)) &&
661 kadm5_modify_policy_internal(handle->lhandle, &opol,
662 KADM5_REF_COUNT))) ||
665 kadm5_modify_policy_internal(handle->lhandle, &npol,
669 if ((mask & KADM5_ATTRIBUTES))
670 kdb.attributes = entry->attributes;
671 if ((mask & KADM5_MAX_LIFE))
672 kdb.max_life = entry->max_life;
673 if ((mask & KADM5_PRINC_EXPIRE_TIME))
674 kdb.expiration = entry->princ_expire_time;
675 if (mask & KADM5_PW_EXPIRATION)
676 kdb.pw_expiration = entry->pw_expiration;
677 if (mask & KADM5_MAX_RLIFE)
678 kdb.max_renewable_life = entry->max_renewable_life;
680 if((mask & KADM5_KVNO)) {
681 for (i = 0; i < kdb.n_key_data; i++)
682 kdb.key_data[i].key_data_kvno = entry->kvno;
685 if (mask & KADM5_TL_DATA) {
688 /* may have to change the version number of the API. Updates the list with the given tl_data rather than over-writting */
690 for (tl = entry->tl_data; tl;
691 tl = tl->tl_data_next)
693 ret = krb5_dbe_update_tl_data(handle->context, &kdb, tl);
702 * Setting entry->fail_auth_count to 0 can be used to manually unlock
703 * an account. It is not possible to set fail_auth_count to any other
704 * value using kadmin.
706 if (mask & KADM5_FAIL_AUTH_COUNT) {
707 if (entry->fail_auth_count != 0) {
708 ret = KADM5_BAD_SERVER_PARAMS;
712 kdb.fail_auth_count = 0;
715 /* let the mask propagate to the database provider */
718 ret = kdb_put_entry(handle, &kdb, &adb);
724 ret2 = kadm5_free_policy_ent(handle->lhandle, &opol);
725 ret = ret ? ret : ret2;
728 ret2 = kadm5_free_policy_ent(handle->lhandle, &npol);
729 ret = ret ? ret : ret2;
731 kdb_free_entry(handle, &kdb, &adb);
736 kadm5_rename_principal(void *server_handle,
737 krb5_principal source, krb5_principal target)
740 osa_princ_ent_rec adb;
742 kadm5_server_handle_t handle = server_handle;
744 CHECK_HANDLE(server_handle);
746 krb5_clear_error_message(handle->context);
748 if (source == NULL || target == NULL)
751 if ((ret = kdb_get_entry(handle, target, &kdb, &adb)) == 0) {
752 kdb_free_entry(handle, &kdb, &adb);
756 if ((ret = kdb_get_entry(handle, source, &kdb, &adb)))
759 /* this is kinda gross, but unavoidable */
761 for (i=0; i<kdb.n_key_data; i++) {
762 if ((kdb.key_data[i].key_data_ver == 1) ||
763 (kdb.key_data[i].key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL)) {
764 ret = KADM5_NO_RENAME_SALT;
769 kadm5_free_principal(handle->context, kdb.princ);
770 ret = kadm5_copy_principal(handle->context, target, &kdb.princ);
772 kdb.princ = NULL; /* so freeing the dbe doesn't lose */
776 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
779 ret = kdb_delete_entry(handle, source);
782 kdb_free_entry(handle, &kdb, &adb);
787 kadm5_get_principal(void *server_handle, krb5_principal principal,
788 kadm5_principal_ent_t entry,
792 osa_princ_ent_rec adb;
793 krb5_error_code ret = 0;
796 kadm5_server_handle_t handle = server_handle;
798 CHECK_HANDLE(server_handle);
800 krb5_clear_error_message(handle->context);
803 * In version 1, all the defined fields are always returned.
804 * entry is a pointer to a kadm5_principal_ent_t_v1 that should be
805 * filled with allocated memory.
809 memset(entry, 0, sizeof(*entry));
811 if (principal == NULL)
814 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
817 if ((mask & KADM5_POLICY) &&
818 adb.policy && (adb.aux_attributes & KADM5_POLICY)) {
819 if ((entry->policy = strdup(adb.policy)) == NULL) {
825 if (mask & KADM5_AUX_ATTRIBUTES)
826 entry->aux_attributes = adb.aux_attributes;
828 if ((mask & KADM5_PRINCIPAL) &&
829 (ret = krb5_copy_principal(handle->context, kdb.princ,
830 &entry->principal))) {
834 if (mask & KADM5_PRINC_EXPIRE_TIME)
835 entry->princ_expire_time = kdb.expiration;
837 if ((mask & KADM5_LAST_PWD_CHANGE) &&
838 (ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb,
839 &(entry->last_pwd_change)))) {
843 if (mask & KADM5_PW_EXPIRATION)
844 entry->pw_expiration = kdb.pw_expiration;
845 if (mask & KADM5_MAX_LIFE)
846 entry->max_life = kdb.max_life;
848 /* this is a little non-sensical because the function returns two */
849 /* values that must be checked separately against the mask */
850 if ((mask & KADM5_MOD_NAME) || (mask & KADM5_MOD_TIME)) {
851 ret = krb5_dbe_lookup_mod_princ_data(handle->context, &kdb,
858 if (! (mask & KADM5_MOD_TIME))
860 if (! (mask & KADM5_MOD_NAME)) {
861 krb5_free_principal(handle->context, entry->principal);
862 entry->principal = NULL;
866 if (mask & KADM5_ATTRIBUTES)
867 entry->attributes = kdb.attributes;
869 if (mask & KADM5_KVNO)
870 for (entry->kvno = 0, i=0; i<kdb.n_key_data; i++)
871 if (kdb.key_data[i].key_data_kvno > entry->kvno)
872 entry->kvno = kdb.key_data[i].key_data_kvno;
874 ret = krb5_dbe_get_mkvno(handle->context, &kdb, master_keylist,
879 if (mask & KADM5_MAX_RLIFE)
880 entry->max_renewable_life = kdb.max_renewable_life;
881 if (mask & KADM5_LAST_SUCCESS)
882 entry->last_success = kdb.last_success;
883 if (mask & KADM5_LAST_FAILED)
884 entry->last_failed = kdb.last_failed;
885 if (mask & KADM5_FAIL_AUTH_COUNT)
886 entry->fail_auth_count = kdb.fail_auth_count;
887 if (mask & KADM5_TL_DATA) {
888 krb5_tl_data *tl, *tl2;
890 entry->tl_data = NULL;
894 if (tl->tl_data_type > 255) {
895 if ((tl2 = dup_tl_data(tl)) == NULL) {
899 tl2->tl_data_next = entry->tl_data;
900 entry->tl_data = tl2;
904 tl = tl->tl_data_next;
907 if (mask & KADM5_KEY_DATA) {
908 entry->n_key_data = kdb.n_key_data;
909 if(entry->n_key_data) {
910 entry->key_data = malloc(entry->n_key_data*sizeof(krb5_key_data));
911 if (entry->key_data == NULL) {
916 entry->key_data = NULL;
918 for (i = 0; i < entry->n_key_data; i++)
919 ret = krb5_copy_key_data_contents(handle->context,
921 &entry->key_data[i]);
929 if (ret && entry->principal) {
930 krb5_free_principal(handle->context, entry->principal);
931 entry->principal = NULL;
933 kdb_free_entry(handle, &kdb, &adb);
939 * Function: check_pw_reuse
941 * Purpose: Check if a key appears in a list of keys, in order to
942 * enforce password history.
946 * context (r) the krb5 context
947 * hist_keyblock (r) the key that hist_key_data is
949 * n_new_key_data (r) length of new_key_data
950 * new_key_data (r) keys to check against
951 * pw_hist_data, encrypted in hist_keyblock
952 * n_pw_hist_data (r) length of pw_hist_data
953 * pw_hist_data (r) passwords to check new_key_data against
956 * For each new_key in new_key_data:
957 * decrypt new_key with the master_keyblock
958 * for each password in pw_hist_data:
959 * for each hist_key in password:
960 * decrypt hist_key with hist_keyblock
961 * compare the new_key and hist_key
963 * Returns krb5 errors, KADM5_PASS_RESUSE if a key in
964 * new_key_data is the same as a key in pw_hist_data, or 0.
967 check_pw_reuse(krb5_context context,
969 krb5_keyblock *hist_keyblock,
970 int n_new_key_data, krb5_key_data *new_key_data,
971 unsigned int n_pw_hist_data, osa_pw_hist_ent *pw_hist_data)
974 krb5_keyblock newkey, histkey;
977 for (x = 0; x < n_new_key_data; x++) {
978 ret = krb5_dbekd_decrypt_key_data(context,
984 for (y = 0; y < n_pw_hist_data; y++) {
985 for (z = 0; z < pw_hist_data[y].n_key_data; z++) {
986 ret = krb5_dbekd_decrypt_key_data(context,
988 &pw_hist_data[y].key_data[z],
993 if ((newkey.length == histkey.length) &&
994 (newkey.enctype == histkey.enctype) &&
995 (memcmp(newkey.contents, histkey.contents,
996 histkey.length) == 0)) {
997 krb5_free_keyblock_contents(context, &histkey);
998 krb5_free_keyblock_contents(context, &newkey);
1000 return(KADM5_PASS_REUSE);
1002 krb5_free_keyblock_contents(context, &histkey);
1005 krb5_free_keyblock_contents(context, &newkey);
1012 * Function: create_history_entry
1014 * Purpose: Creates a password history entry from an array of
1019 * context (r) krb5_context to use
1020 * mkey (r) master keyblock to decrypt key data with
1021 * hist_key (r) history keyblock to encrypt key data with
1022 * n_key_data (r) number of elements in key_data
1023 * key_data (r) keys to add to the history entry
1024 * hist (w) history entry to fill in
1028 * hist->key_data is allocated to store n_key_data key_datas. Each
1029 * element of key_data is decrypted with master_keyblock, re-encrypted
1030 * in hist_key, and added to hist->key_data. hist->n_key_data is
1031 * set to n_key_data.
1034 int create_history_entry(krb5_context context, krb5_keyblock *mkey,
1035 krb5_keyblock *hist_key, int n_key_data,
1036 krb5_key_data *key_data, osa_pw_hist_ent *hist)
1042 hist->key_data = (krb5_key_data*)malloc(n_key_data*sizeof(krb5_key_data));
1043 if (hist->key_data == NULL)
1045 memset(hist->key_data, 0, n_key_data*sizeof(krb5_key_data));
1047 for (i = 0; i < n_key_data; i++) {
1048 ret = krb5_dbekd_decrypt_key_data(context,
1055 ret = krb5_dbekd_encrypt_key_data(context, hist_key,
1057 key_data[i].key_data_kvno,
1058 &hist->key_data[i]);
1062 krb5_free_keyblock_contents(context, &key);
1063 /* krb5_free_keysalt(context, &salt); */
1066 hist->n_key_data = n_key_data;
1071 void free_history_entry(krb5_context context, osa_pw_hist_ent *hist)
1075 for (i = 0; i < hist->n_key_data; i++)
1076 krb5_free_key_data_contents(context, &hist->key_data[i]);
1077 free(hist->key_data);
1081 * Function: add_to_history
1083 * Purpose: Adds a password to a principal's password history.
1087 * context (r) krb5_context to use
1088 * hist_kvno (r) kvno of current history key
1089 * adb (r/w) admin principal entry to add keys to
1090 * pol (r) adb's policy
1091 * pw (r) keys for the password to add to adb's key history
1095 * add_to_history adds a single password to adb's password history.
1096 * pw contains n_key_data keys in its key_data, in storage should be
1097 * allocated but not freed by the caller (XXX blech!).
1099 * This function maintains adb->old_keys as a circular queue. It
1100 * starts empty, and grows each time this function is called until it
1101 * is pol->pw_history_num items long. adb->old_key_len holds the
1102 * number of allocated entries in the array, and must therefore be [0,
1103 * pol->pw_history_num). adb->old_key_next is the index into the
1104 * array where the next element should be written, and must be [0,
1105 * adb->old_key_len).
1107 static kadm5_ret_t add_to_history(krb5_context context,
1108 krb5_kvno hist_kvno,
1109 osa_princ_ent_t adb,
1110 kadm5_policy_ent_t pol,
1111 osa_pw_hist_ent *pw)
1113 osa_pw_hist_ent *histp;
1115 unsigned int i, knext, nkeys;
1117 nhist = pol->pw_history_num;
1118 /* A history of 1 means just check the current password */
1122 if (adb->admin_history_kvno != hist_kvno) {
1123 /* The history key has changed since the last password change, so we
1124 * have to reset the password history. */
1125 free(adb->old_keys);
1126 adb->old_keys = NULL;
1127 adb->old_key_len = 0;
1128 adb->old_key_next = 0;
1129 adb->admin_history_kvno = hist_kvno;
1132 nkeys = adb->old_key_len;
1133 knext = adb->old_key_next;
1134 /* resize the adb->old_keys array if necessary */
1135 if (nkeys + 1 < nhist) {
1136 if (adb->old_keys == NULL) {
1137 adb->old_keys = (osa_pw_hist_ent *)
1138 malloc((nkeys + 1) * sizeof (osa_pw_hist_ent));
1140 adb->old_keys = (osa_pw_hist_ent *)
1141 realloc(adb->old_keys,
1142 (nkeys + 1) * sizeof (osa_pw_hist_ent));
1144 if (adb->old_keys == NULL)
1147 memset(&adb->old_keys[nkeys], 0, sizeof(osa_pw_hist_ent));
1148 nkeys = ++adb->old_key_len;
1150 * To avoid losing old keys, shift forward each entry after
1153 for (i = nkeys - 1; i > knext; i--) {
1154 adb->old_keys[i] = adb->old_keys[i - 1];
1156 memset(&adb->old_keys[knext], 0, sizeof(osa_pw_hist_ent));
1157 } else if (nkeys + 1 > nhist) {
1159 * The policy must have changed! Shrink the array.
1160 * Can't simply realloc() down, since it might be wrapped.
1161 * To understand the arithmetic below, note that we are
1162 * copying into new positions 0 .. N-1 from old positions
1163 * old_key_next-N .. old_key_next-1, modulo old_key_len,
1164 * where N = pw_history_num - 1 is the length of the
1165 * shortened list. Matt Crawford, FNAL
1168 * M = adb->old_key_len, N = pol->pw_history_num - 1
1170 * tmp[0] .. tmp[N-1] = old[(knext-N)%M] .. old[(knext-1)%M]
1175 tmp = (osa_pw_hist_ent *)
1176 malloc((nhist - 1) * sizeof (osa_pw_hist_ent));
1179 for (i = 0; i < nhist - 1; i++) {
1181 * Add nkeys once before taking remainder to avoid
1184 j = (i + nkeys + knext - (nhist - 1)) % nkeys;
1185 tmp[i] = adb->old_keys[j];
1187 /* Now free the ones we don't keep (the oldest ones) */
1188 for (i = 0; i < nkeys - (nhist - 1); i++) {
1189 j = (i + nkeys + knext) % nkeys;
1190 histp = &adb->old_keys[j];
1191 for (j = 0; j < histp->n_key_data; j++) {
1192 krb5_free_key_data_contents(context, &histp->key_data[j]);
1194 free(histp->key_data);
1196 free(adb->old_keys);
1197 adb->old_keys = tmp;
1198 nkeys = adb->old_key_len = nhist - 1;
1199 knext = adb->old_key_next = 0;
1203 * If nhist decreased since the last password change, and nkeys+1
1204 * is less than the previous nhist, it is possible for knext to
1205 * index into unallocated space. This condition would not be
1206 * caught by the resizing code above.
1208 if (knext + 1 > nkeys)
1209 knext = adb->old_key_next = 0;
1210 /* free the old pw history entry if it contains data */
1211 histp = &adb->old_keys[knext];
1212 for (i = 0; i < histp->n_key_data; i++)
1213 krb5_free_key_data_contents(context, &histp->key_data[i]);
1214 free(histp->key_data);
1216 /* store the new entry */
1217 adb->old_keys[knext] = *pw;
1219 /* update the next pointer */
1220 if (++adb->old_key_next == nhist - 1)
1221 adb->old_key_next = 0;
1226 /* FIXME: don't use global variable for this */
1227 krb5_boolean use_password_server = 0;
1229 #ifdef USE_PASSWORD_SERVER
1231 kadm5_use_password_server (void)
1233 return use_password_server;
1238 kadm5_set_use_password_server (void)
1240 use_password_server = 1;
1243 #ifdef USE_PASSWORD_SERVER
1246 * kadm5_launch_task () runs a program (task_path) to synchronize the
1247 * Apple password server with the Kerberos database. Password server
1248 * programs can receive arguments on the command line (task_argv)
1249 * and a block of data via stdin (data_buffer).
1251 * Because a failure to communicate with the tool results in the
1252 * password server falling out of sync with the database,
1253 * kadm5_launch_task() always fails if it can't talk to the tool.
1257 kadm5_launch_task (krb5_context context,
1258 const char *task_path, char * const task_argv[],
1264 ret = pipe (data_pipe);
1269 pid_t pid = fork ();
1272 close (data_pipe[0]);
1273 close (data_pipe[1]);
1274 } else if (pid == 0) {
1277 if (dup2 (data_pipe[0], STDIN_FILENO) == -1)
1280 close (data_pipe[0]);
1281 close (data_pipe[1]);
1283 execv (task_path, task_argv);
1285 _exit (1); /* Fail if execv fails */
1292 close (data_pipe[0]);
1294 /* Write out the buffer to the child, add \n */
1296 if (krb5_net_write (context, data_pipe[1], buffer, strlen (buffer)) < 0
1297 || krb5_net_write (context, data_pipe[1], "\n", 1) < 0)
1299 /* kill the child to make sure waitpid() won't hang later */
1301 kill (pid, SIGKILL);
1304 close (data_pipe[1]);
1306 waitpid (pid, &status, 0);
1309 if (WIFEXITED (status)) {
1310 /* child read password and exited. Check the return value. */
1311 if ((WEXITSTATUS (status) != 0) && (WEXITSTATUS (status) != 252)) {
1312 ret = KRB5KDC_ERR_POLICY; /* password change rejected */
1315 /* child read password but crashed or was killed */
1316 ret = KRB5KRB_ERR_GENERIC; /* FIXME: better error */
1328 kadm5_chpass_principal(void *server_handle,
1329 krb5_principal principal, char *password)
1332 kadm5_chpass_principal_3(server_handle, principal, FALSE,
1337 kadm5_chpass_principal_3(void *server_handle,
1338 krb5_principal principal, krb5_boolean keepold,
1339 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1343 kadm5_policy_ent_rec pol;
1344 osa_princ_ent_rec adb;
1345 krb5_db_entry kdb, kdb_save;
1346 int ret, ret2, last_pwd, hist_added;
1348 kadm5_server_handle_t handle = server_handle;
1349 osa_pw_hist_ent hist;
1350 krb5_keyblock *act_mkey, hist_keyblock;
1351 krb5_kvno act_kvno, hist_kvno;
1353 CHECK_HANDLE(server_handle);
1355 krb5_clear_error_message(handle->context);
1358 memset(&hist, 0, sizeof(hist));
1359 memset(&hist_keyblock, 0, sizeof(hist_keyblock));
1361 if (principal == NULL || password == NULL)
1363 if ((krb5_principal_compare(handle->context,
1364 principal, hist_princ)) == TRUE)
1365 return KADM5_PROTECT_PRINCIPAL;
1367 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1370 /* we are going to need the current keys after the new keys are set */
1371 if ((ret = kdb_get_entry(handle, principal, &kdb_save, NULL))) {
1372 kdb_free_entry(handle, &kdb, &adb);
1376 if ((adb.aux_attributes & KADM5_POLICY)) {
1377 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &pol)))
1382 if ((ret = passwd_check(handle, password, adb.aux_attributes &
1383 KADM5_POLICY, &pol, principal)))
1386 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
1387 active_mkey_list, &act_kvno, &act_mkey);
1391 ret = krb5_dbe_cpw(handle->context, act_mkey,
1392 n_ks_tuple?ks_tuple:handle->params.keysalts,
1393 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
1394 password, 0 /* increment kvno */,
1399 ret = krb5_dbe_update_mkvno(handle->context, &kdb, act_kvno);
1403 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1405 ret = krb5_timeofday(handle->context, &now);
1409 if ((adb.aux_attributes & KADM5_POLICY)) {
1410 /* the policy was loaded before */
1412 ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1419 * The spec says this check is overridden if the caller has
1420 * modify privilege. The admin server therefore makes this
1421 * check itself (in chpass_principal_wrapper, misc.c). A
1422 * local caller implicitly has all authorization bits.
1424 if ((now - last_pwd) < pol.pw_min_life &&
1425 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1426 ret = KADM5_PASS_TOOSOON;
1431 ret = kdb_get_hist_key(handle, &hist_keyblock, &hist_kvno);
1435 ret = create_history_entry(handle->context,
1436 act_mkey, &hist_keyblock,
1437 kdb_save.n_key_data,
1438 kdb_save.key_data, &hist);
1442 ret = check_pw_reuse(handle->context, act_mkey, &hist_keyblock,
1443 kdb.n_key_data, kdb.key_data,
1448 if (pol.pw_history_num > 1) {
1449 /* If hist_kvno has changed since the last password change, we
1450 * can't check the history. */
1451 if (adb.admin_history_kvno == hist_kvno) {
1452 ret = check_pw_reuse(handle->context, act_mkey, &hist_keyblock,
1453 kdb.n_key_data, kdb.key_data,
1454 adb.old_key_len, adb.old_keys);
1459 ret = add_to_history(handle->context, hist_kvno, &adb, &pol,
1466 if (pol.pw_max_life)
1467 kdb.pw_expiration = now + pol.pw_max_life;
1469 kdb.pw_expiration = 0;
1471 kdb.pw_expiration = 0;
1474 #ifdef USE_PASSWORD_SERVER
1475 if (kadm5_use_password_server () &&
1476 (krb5_princ_size (handle->context, principal) == 1)) {
1477 krb5_data *princ = krb5_princ_component (handle->context, principal, 0);
1478 const char *path = "/usr/sbin/mkpassdb";
1479 char *argv[] = { "mkpassdb", "-setpassword", NULL, NULL };
1480 char *pstring = NULL;
1483 pstring = malloc ((princ->length + 1) * sizeof (char));
1484 if (pstring == NULL) { ret = ENOMEM; }
1488 memcpy (pstring, princ->data, princ->length);
1489 pstring [princ->length] = '\0';
1492 ret = kadm5_launch_task (handle->context, path, argv, password);
1495 if (pstring != NULL)
1503 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
1507 /* unlock principal on this KDC */
1508 kdb.fail_auth_count = 0;
1510 /* key data and attributes changed, let the database provider know */
1511 kdb.mask = KADM5_KEY_DATA | KADM5_ATTRIBUTES |
1512 KADM5_FAIL_AUTH_COUNT;
1513 /* | KADM5_CPW_FUNCTION */
1515 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1520 if (!hist_added && hist.key_data)
1521 free_history_entry(handle->context, &hist);
1522 kdb_free_entry(handle, &kdb, &adb);
1523 kdb_free_entry(handle, &kdb_save, NULL);
1524 krb5_db_free_principal(handle->context, &kdb, 1);
1525 krb5_free_keyblock_contents(handle->context, &hist_keyblock);
1527 if (have_pol && (ret2 = kadm5_free_policy_ent(handle->lhandle, &pol))
1535 kadm5_randkey_principal(void *server_handle,
1536 krb5_principal principal,
1537 krb5_keyblock **keyblocks,
1541 kadm5_randkey_principal_3(server_handle, principal,
1546 kadm5_randkey_principal_3(void *server_handle,
1547 krb5_principal principal,
1548 krb5_boolean keepold,
1549 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1550 krb5_keyblock **keyblocks,
1554 osa_princ_ent_rec adb;
1556 kadm5_policy_ent_rec pol;
1557 int ret, last_pwd, have_pol = 0;
1558 kadm5_server_handle_t handle = server_handle;
1559 krb5_keyblock *act_mkey;
1564 CHECK_HANDLE(server_handle);
1566 krb5_clear_error_message(handle->context);
1568 if (principal == NULL)
1570 if (krb5_principal_compare(handle->context, principal, hist_princ)) {
1571 /* If changing the history entry, the new entry must have exactly one
1574 return KADM5_PROTECT_PRINCIPAL;
1575 ks_tuple = n_ks_tuple ? ks_tuple : handle->params.keysalts,
1579 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1582 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
1583 active_mkey_list, NULL, &act_mkey);
1587 ret = krb5_dbe_crk(handle->context, act_mkey,
1588 n_ks_tuple?ks_tuple:handle->params.keysalts,
1589 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
1595 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1597 ret = krb5_timeofday(handle->context, &now);
1601 if ((adb.aux_attributes & KADM5_POLICY)) {
1602 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1607 ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1614 * The spec says this check is overridden if the caller has
1615 * modify privilege. The admin server therefore makes this
1616 * check itself (in chpass_principal_wrapper, misc.c). A
1617 * local caller implicitly has all authorization bits.
1619 if((now - last_pwd) < pol.pw_min_life &&
1620 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1621 ret = KADM5_PASS_TOOSOON;
1626 if (pol.pw_max_life)
1627 kdb.pw_expiration = now + pol.pw_max_life;
1629 kdb.pw_expiration = 0;
1631 kdb.pw_expiration = 0;
1634 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
1638 /* unlock principal on this KDC */
1639 kdb.fail_auth_count = 0;
1642 ret = decrypt_key_data(handle->context, act_mkey,
1643 kdb.n_key_data, kdb.key_data,
1649 /* key data changed, let the database provider know */
1650 kdb.mask = KADM5_KEY_DATA | KADM5_FAIL_AUTH_COUNT;
1651 /* | KADM5_RANDKEY_USED */;
1653 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1658 kdb_free_entry(handle, &kdb, &adb);
1660 kadm5_free_policy_ent(handle->lhandle, &pol);
1666 * kadm5_setv4key_principal:
1668 * Set only ONE key of the principal, removing all others. This key
1669 * must have the DES_CBC_CRC enctype and is entered as having the
1670 * krb4 salttype. This is to enable things like kadmind4 to work.
1673 kadm5_setv4key_principal(void *server_handle,
1674 krb5_principal principal,
1675 krb5_keyblock *keyblock)
1678 osa_princ_ent_rec adb;
1680 kadm5_policy_ent_rec pol;
1681 krb5_keysalt keysalt;
1682 int i, k, kvno, ret, have_pol = 0;
1686 kadm5_server_handle_t handle = server_handle;
1687 krb5_key_data tmp_key_data;
1688 krb5_keyblock *act_mkey;
1690 memset( &tmp_key_data, 0, sizeof(tmp_key_data));
1692 CHECK_HANDLE(server_handle);
1694 krb5_clear_error_message(handle->context);
1696 if (principal == NULL || keyblock == NULL)
1698 if (hist_princ && /* this will be NULL when initializing the databse */
1699 ((krb5_principal_compare(handle->context,
1700 principal, hist_princ)) == TRUE))
1701 return KADM5_PROTECT_PRINCIPAL;
1703 if (keyblock->enctype != ENCTYPE_DES_CBC_CRC)
1704 return KADM5_SETV4KEY_INVAL_ENCTYPE;
1706 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1709 for (kvno = 0, i=0; i<kdb.n_key_data; i++)
1710 if (kdb.key_data[i].key_data_kvno > kvno)
1711 kvno = kdb.key_data[i].key_data_kvno;
1713 if (kdb.key_data != NULL)
1714 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
1716 kdb.key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, sizeof(krb5_key_data));
1717 if (kdb.key_data == NULL)
1719 memset(kdb.key_data, 0, sizeof(krb5_key_data));
1721 keysalt.type = KRB5_KDB_SALTTYPE_V4;
1722 /* XXX data.magic? */
1723 keysalt.data.length = 0;
1724 keysalt.data.data = NULL;
1726 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
1727 active_mkey_list, NULL, &act_mkey);
1731 /* use tmp_key_data as temporary location and reallocate later */
1732 ret = krb5_dbekd_encrypt_key_data(handle->context, act_mkey,
1733 keyblock, &keysalt, kvno + 1,
1739 for (k = 0; k < tmp_key_data.key_data_ver; k++) {
1740 kdb.key_data->key_data_type[k] = tmp_key_data.key_data_type[k];
1741 kdb.key_data->key_data_length[k] = tmp_key_data.key_data_length[k];
1742 if (tmp_key_data.key_data_contents[k]) {
1743 kdb.key_data->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]);
1744 if (kdb.key_data->key_data_contents[k] == NULL) {
1745 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
1746 kdb.key_data = NULL;
1751 memcpy (kdb.key_data->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
1753 memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
1754 free (tmp_key_data.key_data_contents[k]);
1755 tmp_key_data.key_data_contents[k] = NULL;
1761 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1763 ret = krb5_timeofday(handle->context, &now);
1767 if ((adb.aux_attributes & KADM5_POLICY)) {
1768 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1775 * The spec says this check is overridden if the caller has
1776 * modify privilege. The admin server therefore makes this
1777 * check itself (in chpass_principal_wrapper, misc.c). A
1778 * local caller implicitly has all authorization bits.
1780 if (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1783 if((now - last_pwd) < pol.pw_min_life &&
1784 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1785 ret = KADM5_PASS_TOOSOON;
1790 if (pol.pw_max_life)
1791 kdb.pw_expiration = now + pol.pw_max_life;
1793 kdb.pw_expiration = 0;
1795 kdb.pw_expiration = 0;
1798 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
1802 /* unlock principal on this KDC */
1803 kdb.fail_auth_count = 0;
1805 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1810 for (i = 0; i < tmp_key_data.key_data_ver; i++) {
1811 if (tmp_key_data.key_data_contents[i]) {
1812 memset (tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]);
1813 free (tmp_key_data.key_data_contents[i]);
1817 kdb_free_entry(handle, &kdb, &adb);
1819 kadm5_free_policy_ent(handle->lhandle, &pol);
1825 kadm5_setkey_principal(void *server_handle,
1826 krb5_principal principal,
1827 krb5_keyblock *keyblocks,
1831 kadm5_setkey_principal_3(server_handle, principal,
1837 kadm5_setkey_principal_3(void *server_handle,
1838 krb5_principal principal,
1839 krb5_boolean keepold,
1840 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1841 krb5_keyblock *keyblocks,
1845 osa_princ_ent_rec adb;
1847 kadm5_policy_ent_rec pol;
1848 krb5_key_data *old_key_data;
1850 int i, j, k, kvno, ret, have_pol = 0;
1854 kadm5_server_handle_t handle = server_handle;
1855 krb5_boolean similar;
1856 krb5_keysalt keysalt;
1857 krb5_key_data tmp_key_data;
1858 krb5_key_data *tptr;
1859 krb5_keyblock *act_mkey;
1861 CHECK_HANDLE(server_handle);
1863 krb5_clear_error_message(handle->context);
1865 if (principal == NULL || keyblocks == NULL)
1867 if (hist_princ && /* this will be NULL when initializing the databse */
1868 ((krb5_principal_compare(handle->context,
1869 principal, hist_princ)) == TRUE))
1870 return KADM5_PROTECT_PRINCIPAL;
1872 for (i = 0; i < n_keys; i++) {
1873 for (j = i+1; j < n_keys; j++) {
1874 if ((ret = krb5_c_enctype_compare(handle->context,
1875 keyblocks[i].enctype,
1876 keyblocks[j].enctype,
1881 if (ks_tuple[i].ks_salttype == ks_tuple[j].ks_salttype)
1882 return KADM5_SETKEY_DUP_ENCTYPES;
1884 return KADM5_SETKEY_DUP_ENCTYPES;
1889 if (n_ks_tuple && n_ks_tuple != n_keys)
1890 return KADM5_SETKEY3_ETYPE_MISMATCH;
1892 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1895 for (kvno = 0, i=0; i<kdb.n_key_data; i++)
1896 if (kdb.key_data[i].key_data_kvno > kvno)
1897 kvno = kdb.key_data[i].key_data_kvno;
1900 old_key_data = kdb.key_data;
1901 n_old_keys = kdb.n_key_data;
1903 if (kdb.key_data != NULL)
1904 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
1906 old_key_data = NULL;
1909 kdb.key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, (n_keys+n_old_keys)
1910 *sizeof(krb5_key_data));
1911 if (kdb.key_data == NULL) {
1916 memset(kdb.key_data, 0, (n_keys+n_old_keys)*sizeof(krb5_key_data));
1919 for (i = 0; i < n_keys; i++) {
1921 keysalt.type = ks_tuple[i].ks_salttype;
1922 keysalt.data.length = 0;
1923 keysalt.data.data = NULL;
1924 if (ks_tuple[i].ks_enctype != keyblocks[i].enctype) {
1925 ret = KADM5_SETKEY3_ETYPE_MISMATCH;
1929 memset (&tmp_key_data, 0, sizeof(tmp_key_data));
1931 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
1932 active_mkey_list, NULL, &act_mkey);
1936 ret = krb5_dbekd_encrypt_key_data(handle->context,
1939 n_ks_tuple ? &keysalt : NULL,
1945 tptr = &kdb.key_data[i];
1946 tptr->key_data_ver = tmp_key_data.key_data_ver;
1947 tptr->key_data_kvno = tmp_key_data.key_data_kvno;
1948 for (k = 0; k < tmp_key_data.key_data_ver; k++) {
1949 tptr->key_data_type[k] = tmp_key_data.key_data_type[k];
1950 tptr->key_data_length[k] = tmp_key_data.key_data_length[k];
1951 if (tmp_key_data.key_data_contents[k]) {
1952 tptr->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]);
1953 if (tptr->key_data_contents[k] == NULL) {
1955 for (i1 = k; i1 < tmp_key_data.key_data_ver; i1++) {
1956 if (tmp_key_data.key_data_contents[i1]) {
1957 memset (tmp_key_data.key_data_contents[i1], 0, tmp_key_data.key_data_length[i1]);
1958 free (tmp_key_data.key_data_contents[i1]);
1965 memcpy (tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
1967 memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
1968 free (tmp_key_data.key_data_contents[k]);
1969 tmp_key_data.key_data_contents[k] = NULL;
1975 /* copy old key data if necessary */
1976 for (i = 0; i < n_old_keys; i++) {
1977 kdb.key_data[i+n_keys] = old_key_data[i];
1978 memset(&old_key_data[i], 0, sizeof (krb5_key_data));
1983 krb5_db_free(handle->context, old_key_data);
1985 /* assert(kdb.n_key_data == n_keys + n_old_keys) */
1986 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1988 if ((ret = krb5_timeofday(handle->context, &now)))
1991 if ((adb.aux_attributes & KADM5_POLICY)) {
1992 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1999 * The spec says this check is overridden if the caller has
2000 * modify privilege. The admin server therefore makes this
2001 * check itself (in chpass_principal_wrapper, misc.c). A
2002 * local caller implicitly has all authorization bits.
2004 if (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
2007 if((now - last_pwd) < pol.pw_min_life &&
2008 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
2009 ret = KADM5_PASS_TOOSOON;
2014 if (pol.pw_max_life)
2015 kdb.pw_expiration = now + pol.pw_max_life;
2017 kdb.pw_expiration = 0;
2019 kdb.pw_expiration = 0;
2022 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now)))
2025 /* unlock principal on this KDC */
2026 kdb.fail_auth_count = 0;
2028 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
2033 kdb_free_entry(handle, &kdb, &adb);
2035 kadm5_free_policy_ent(handle->lhandle, &pol);
2041 * Return the list of keys like kadm5_randkey_principal,
2042 * but don't modify the principal.
2045 kadm5_get_principal_keys(void *server_handle /* IN */,
2046 krb5_principal principal /* IN */,
2047 krb5_keyblock **keyblocks /* OUT */,
2048 int *n_keys /* OUT */)
2051 osa_princ_ent_rec adb;
2053 kadm5_server_handle_t handle = server_handle;
2054 krb5_keyblock *mkey_ptr;
2059 CHECK_HANDLE(server_handle);
2061 if (principal == NULL)
2064 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
2068 if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist, &kdb,
2070 krb5_keylist_node *tmp_mkey_list;
2071 /* try refreshing master key list */
2072 /* XXX it would nice if we had the mkvno here for optimization */
2073 if (krb5_db_fetch_mkey_list(handle->context, master_princ,
2074 &master_keyblock, 0,
2075 &tmp_mkey_list) == 0) {
2076 krb5_dbe_free_key_list(handle->context, master_keylist);
2077 master_keylist = tmp_mkey_list;
2078 if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist,
2079 &kdb, &mkey_ptr))) {
2087 ret = decrypt_key_data(handle->context, mkey_ptr,
2088 kdb.n_key_data, kdb.key_data,
2096 kdb_free_entry(handle, &kdb, &adb);
2103 * Allocate an array of n_key_data krb5_keyblocks, fill in each
2104 * element with the results of decrypting the nth key in key_data with
2105 * mkey, and if n_keys is not NULL fill it in with the
2106 * number of keys decrypted.
2108 static int decrypt_key_data(krb5_context context, krb5_keyblock *mkey,
2109 int n_key_data, krb5_key_data *key_data,
2110 krb5_keyblock **keyblocks, int *n_keys)
2112 krb5_keyblock *keys;
2115 keys = (krb5_keyblock *) malloc(n_key_data*sizeof(krb5_keyblock));
2118 memset(keys, 0, n_key_data*sizeof(krb5_keyblock));
2120 for (i = 0; i < n_key_data; i++) {
2121 ret = krb5_dbekd_decrypt_key_data(context, mkey,
2125 for (; i >= 0; i--) {
2126 if (keys[i].contents) {
2127 memset (keys[i].contents, 0, keys[i].length);
2128 free( keys[i].contents );
2132 memset(keys, 0, n_key_data*sizeof(krb5_keyblock));
2140 *n_keys = n_key_data;
2146 * Function: kadm5_decrypt_key
2148 * Purpose: Retrieves and decrypts a principal key.
2152 * server_handle (r) kadm5 handle
2153 * entry (r) principal retrieved with kadm5_get_principal
2154 * ktype (r) enctype to search for, or -1 to ignore
2155 * stype (r) salt type to search for, or -1 to ignore
2156 * kvno (r) kvno to search for, -1 for max, 0 for max
2157 * only if it also matches ktype and stype
2158 * keyblock (w) keyblock to fill in
2159 * keysalt (w) keysalt to fill in, or NULL
2160 * kvnop (w) kvno to fill in, or NULL
2162 * Effects: Searches the key_data array of entry, which must have been
2163 * retrived with kadm5_get_principal with the KADM5_KEY_DATA mask, to
2164 * find a key with a specified enctype, salt type, and kvno in a
2165 * principal entry. If not found, return ENOENT. Otherwise, decrypt
2166 * it with the master key, and return the key in keyblock, the salt
2167 * in salttype, and the key version number in kvno.
2169 * If ktype or stype is -1, it is ignored for the search. If kvno is
2170 * -1, ktype and stype are ignored and the key with the max kvno is
2171 * returned. If kvno is 0, only the key with the max kvno is returned
2172 * and only if it matches the ktype and stype; otherwise, ENOENT is
2175 kadm5_ret_t kadm5_decrypt_key(void *server_handle,
2176 kadm5_principal_ent_t entry, krb5_int32
2177 ktype, krb5_int32 stype, krb5_int32
2178 kvno, krb5_keyblock *keyblock,
2179 krb5_keysalt *keysalt, int *kvnop)
2181 kadm5_server_handle_t handle = server_handle;
2182 krb5_db_entry dbent;
2183 krb5_key_data *key_data;
2184 krb5_keyblock *mkey_ptr;
2187 CHECK_HANDLE(server_handle);
2189 if (entry->n_key_data == 0 || entry->key_data == NULL)
2192 /* find_enctype only uses these two fields */
2193 dbent.n_key_data = entry->n_key_data;
2194 dbent.key_data = entry->key_data;
2195 if ((ret = krb5_dbe_find_enctype(handle->context, &dbent, ktype,
2196 stype, kvno, &key_data)))
2199 /* find_mkey only uses this field */
2200 dbent.tl_data = entry->tl_data;
2201 if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist, &dbent,
2203 krb5_keylist_node *tmp_mkey_list;
2204 /* try refreshing master key list */
2205 /* XXX it would nice if we had the mkvno here for optimization */
2206 if (krb5_db_fetch_mkey_list(handle->context, master_princ,
2207 &master_keyblock, 0, &tmp_mkey_list) == 0) {
2208 krb5_dbe_free_key_list(handle->context, master_keylist);
2209 master_keylist = tmp_mkey_list;
2210 if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist,
2211 &dbent, &mkey_ptr))) {
2219 if ((ret = krb5_dbekd_decrypt_key_data(handle->context,
2221 keyblock, keysalt)))
2225 * Coerce the enctype of the output keyblock in case we got an
2226 * inexact match on the enctype; this behavior will go away when
2227 * the key storage architecture gets redesigned for 1.3.
2230 keyblock->enctype = ktype;
2233 *kvnop = key_data->key_data_kvno;