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>
14 #include <kadm5/admin.h>
18 #include "server_internal.h"
21 #ifdef USE_PASSWORD_SERVER
28 #include <valgrind/memcheck.h>
30 #define VALGRIND_CHECK_DEFINED(LVALUE) ((void)0)
33 extern krb5_principal master_princ;
34 extern krb5_principal hist_princ;
35 extern krb5_keyblock master_keyblock;
36 extern krb5_keylist_node *master_keylist;
37 extern krb5_actkvno_node *active_mkey_list;
38 extern krb5_keyblock hist_key;
39 extern krb5_db_entry master_db;
40 extern krb5_db_entry hist_db;
41 extern krb5_kvno hist_kvno;
43 static int decrypt_key_data(krb5_context context, krb5_keyblock *mkey,
44 int n_key_data, krb5_key_data *key_data,
45 krb5_keyblock **keyblocks, int *n_keys);
47 static krb5_error_code
48 kadm5_copy_principal(krb5_context context, krb5_const_principal inprinc, krb5_principal *outprinc)
50 register krb5_principal tempprinc;
51 register int i, nelems;
53 tempprinc = (krb5_principal)krb5_db_alloc(context, NULL, sizeof(krb5_principal_data));
58 VALGRIND_CHECK_DEFINED(*inprinc);
59 memcpy(tempprinc, inprinc, sizeof(krb5_principal_data));
61 nelems = (int) krb5_princ_size(context, inprinc);
62 tempprinc->data = krb5_db_alloc(context, NULL, nelems * sizeof(krb5_data));
63 if (tempprinc->data == 0) {
64 krb5_db_free(context, (char *)tempprinc);
68 for (i = 0; i < nelems; i++) {
69 unsigned int len = krb5_princ_component(context, inprinc, i)->length;
70 krb5_princ_component(context, tempprinc, i)->length = len;
71 if (((krb5_princ_component(context, tempprinc, i)->data =
72 krb5_db_alloc(context, NULL, len)) == 0) && len) {
74 krb5_db_free(context, krb5_princ_component(context, tempprinc, i)->data);
75 krb5_db_free (context, tempprinc->data);
76 krb5_db_free (context, tempprinc);
80 memcpy(krb5_princ_component(context, tempprinc, i)->data,
81 krb5_princ_component(context, inprinc, i)->data, len);
82 krb5_princ_component(context, tempprinc, i)->magic = KV5M_DATA;
85 tempprinc->realm.data =
86 krb5_db_alloc(context, NULL, tempprinc->realm.length = inprinc->realm.length);
87 if (!tempprinc->realm.data && tempprinc->realm.length) {
88 for (i = 0; i < nelems; i++)
89 krb5_db_free(context, krb5_princ_component(context, tempprinc, i)->data);
90 krb5_db_free(context, tempprinc->data);
91 krb5_db_free(context, tempprinc);
94 if (tempprinc->realm.length)
95 memcpy(tempprinc->realm.data, inprinc->realm.data,
96 inprinc->realm.length);
98 *outprinc = tempprinc;
103 kadm5_free_principal(krb5_context context, krb5_principal val)
105 register krb5_int32 i;
111 i = krb5_princ_size(context, val);
113 krb5_db_free(context, krb5_princ_component(context, val, i)->data);
114 krb5_db_free(context, val->data);
117 krb5_db_free(context, val->realm.data);
118 krb5_db_free(context, val);
122 * XXX Functions that ought to be in libkrb5.a, but aren't.
124 kadm5_ret_t krb5_copy_key_data_contents(context, from, to)
125 krb5_context context;
126 krb5_key_data *from, *to;
132 idx = (from->key_data_ver == 1 ? 1 : 2);
134 for (i = 0; i < idx; i++) {
135 if ( from->key_data_length[i] ) {
136 to->key_data_contents[i] = malloc(from->key_data_length[i]);
137 if (to->key_data_contents[i] == NULL) {
138 for (i = 0; i < idx; i++) {
139 if (to->key_data_contents[i]) {
140 memset(to->key_data_contents[i], 0,
141 to->key_data_length[i]);
142 free(to->key_data_contents[i]);
147 memcpy(to->key_data_contents[i], from->key_data_contents[i],
148 from->key_data_length[i]);
154 static krb5_tl_data *dup_tl_data(krb5_tl_data *tl)
158 n = (krb5_tl_data *) malloc(sizeof(krb5_tl_data));
161 n->tl_data_contents = malloc(tl->tl_data_length);
162 if (n->tl_data_contents == NULL) {
166 memcpy(n->tl_data_contents, tl->tl_data_contents, tl->tl_data_length);
167 n->tl_data_type = tl->tl_data_type;
168 n->tl_data_length = tl->tl_data_length;
169 n->tl_data_next = NULL;
173 /* This is in lib/kdb/kdb_cpw.c, but is static */
174 static void cleanup_key_data(context, count, data)
175 krb5_context context;
177 krb5_key_data * data;
181 for (i = 0; i < count; i++)
182 for (j = 0; j < data[i].key_data_ver; j++)
183 if (data[i].key_data_length[j])
184 krb5_db_free(context, data[i].key_data_contents[j]);
185 krb5_db_free(context, data);
189 kadm5_create_principal(void *server_handle,
190 kadm5_principal_ent_t entry, long mask,
194 kadm5_create_principal_3(server_handle, entry, mask,
198 kadm5_create_principal_3(void *server_handle,
199 kadm5_principal_ent_t entry, long mask,
200 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
204 osa_princ_ent_rec adb;
205 kadm5_policy_ent_rec polent;
207 krb5_tl_data *tl_data_orig, *tl_data_tail;
209 kadm5_server_handle_t handle = server_handle;
210 krb5_keyblock *act_mkey;
213 CHECK_HANDLE(server_handle);
215 krb5_clear_error_message(handle->context);
218 * Argument sanity checking, and opening up the DB
220 if(!(mask & KADM5_PRINCIPAL) || (mask & KADM5_MOD_NAME) ||
221 (mask & KADM5_MOD_TIME) || (mask & KADM5_LAST_PWD_CHANGE) ||
222 (mask & KADM5_MKVNO) || (mask & KADM5_POLICY_CLR) ||
223 (mask & KADM5_AUX_ATTRIBUTES) || (mask & KADM5_KEY_DATA) ||
224 (mask & KADM5_LAST_SUCCESS) || (mask & KADM5_LAST_FAILED) ||
225 (mask & KADM5_FAIL_AUTH_COUNT))
226 return KADM5_BAD_MASK;
227 if((mask & ~ALL_PRINC_MASK))
228 return KADM5_BAD_MASK;
229 if (entry == (kadm5_principal_ent_t) NULL || password == NULL)
233 * Check to see if the principal exists
235 ret = kdb_get_entry(handle, entry->principal, &kdb, &adb);
238 case KADM5_UNK_PRINC:
241 kdb_free_entry(handle, &kdb, &adb);
247 memset(&kdb, 0, sizeof(krb5_db_entry));
248 memset(&adb, 0, sizeof(osa_princ_ent_rec));
251 * If a policy was specified, load it.
252 * If we can not find the one specified return an error
254 if ((mask & KADM5_POLICY)) {
255 if ((ret = kadm5_get_policy(handle->lhandle, entry->policy,
256 &polent)) != KADM5_OK) {
258 return KADM5_BAD_POLICY;
263 if ((ret = passwd_check(handle, password, (mask & KADM5_POLICY),
264 &polent, entry->principal))) {
265 if (mask & KADM5_POLICY)
266 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
270 * Start populating the various DB fields, using the
271 * "defaults" for fields that were not specified by the
274 if ((ret = krb5_timeofday(handle->context, &now))) {
275 if (mask & KADM5_POLICY)
276 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
280 kdb.magic = KRB5_KDB_MAGIC_NUMBER;
281 kdb.len = KRB5_KDB_V1_BASE_LENGTH; /* gag me with a chainsaw */
283 if ((mask & KADM5_ATTRIBUTES))
284 kdb.attributes = entry->attributes;
286 kdb.attributes = handle->params.flags;
288 if ((mask & KADM5_MAX_LIFE))
289 kdb.max_life = entry->max_life;
291 kdb.max_life = handle->params.max_life;
293 if (mask & KADM5_MAX_RLIFE)
294 kdb.max_renewable_life = entry->max_renewable_life;
296 kdb.max_renewable_life = handle->params.max_rlife;
298 if ((mask & KADM5_PRINC_EXPIRE_TIME))
299 kdb.expiration = entry->princ_expire_time;
301 kdb.expiration = handle->params.expiration;
303 kdb.pw_expiration = 0;
304 if ((mask & KADM5_POLICY)) {
305 if(polent.pw_max_life)
306 kdb.pw_expiration = now + polent.pw_max_life;
308 kdb.pw_expiration = 0;
310 if ((mask & KADM5_PW_EXPIRATION))
311 kdb.pw_expiration = entry->pw_expiration;
313 kdb.last_success = 0;
315 kdb.fail_auth_count = 0;
317 /* this is kind of gross, but in order to free the tl data, I need
318 to free the entire kdb entry, and that will try to free the
321 if ((ret = kadm5_copy_principal(handle->context,
322 entry->principal, &(kdb.princ)))) {
323 if (mask & KADM5_POLICY)
324 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
328 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now))) {
329 krb5_db_free_principal(handle->context, &kdb, 1);
330 if (mask & KADM5_POLICY)
331 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
335 if (mask & KADM5_TL_DATA) {
336 /* splice entry->tl_data onto the front of kdb.tl_data */
337 tl_data_orig = kdb.tl_data;
338 for (tl_data_tail = entry->tl_data; tl_data_tail;
339 tl_data_tail = tl_data_tail->tl_data_next)
341 ret = krb5_dbe_update_tl_data(handle->context, &kdb, tl_data_tail);
344 krb5_db_free_principal(handle->context, &kdb, 1);
345 if (mask & KADM5_POLICY)
346 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
352 /* initialize the keys */
354 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
355 active_mkey_list, &act_kvno, &act_mkey);
357 krb5_db_free_principal(handle->context, &kdb, 1);
358 if (mask & KADM5_POLICY)
359 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
363 if ((ret = krb5_dbe_cpw(handle->context, act_mkey,
364 n_ks_tuple?ks_tuple:handle->params.keysalts,
365 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
367 (mask & KADM5_KVNO)?entry->kvno:1,
369 krb5_db_free_principal(handle->context, &kdb, 1);
370 if (mask & KADM5_POLICY)
371 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
375 /* Record the master key VNO used to encrypt this entry's keys */
376 ret = krb5_dbe_update_mkvno(handle->context, &kdb, act_kvno);
379 krb5_db_free_principal(handle->context, &kdb, 1);
380 if (mask & KADM5_POLICY)
381 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
385 /* populate the admin-server-specific fields. In the OV server,
386 this used to be in a separate database. Since there's already
387 marshalling code for the admin fields, to keep things simple,
388 I'm going to keep it, and make all the admin stuff occupy a
389 single tl_data record, */
391 adb.admin_history_kvno = hist_kvno;
392 if ((mask & KADM5_POLICY)) {
393 adb.aux_attributes = KADM5_POLICY;
395 /* this does *not* need to be strdup'ed, because adb is xdr */
396 /* encoded in osa_adb_create_princ, and not ever freed */
398 adb.policy = entry->policy;
401 /* increment the policy ref count, if any */
403 if ((mask & KADM5_POLICY)) {
404 polent.policy_refcnt++;
405 if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent,
408 krb5_db_free_principal(handle->context, &kdb, 1);
409 if (mask & KADM5_POLICY)
410 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
415 /* In all cases key and the principal data is set, let the database provider know */
416 kdb.mask = mask | KADM5_KEY_DATA | KADM5_PRINCIPAL ;
418 /* store the new db entry */
419 ret = kdb_put_entry(handle, &kdb, &adb);
421 krb5_db_free_principal(handle->context, &kdb, 1);
424 if ((mask & KADM5_POLICY)) {
425 /* decrement the policy ref count */
427 polent.policy_refcnt--;
429 * if this fails, there's nothing we can do anyway. the
430 * policy refcount wil be too high.
432 (void) kadm5_modify_policy_internal(handle->lhandle, &polent,
436 if (mask & KADM5_POLICY)
437 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
441 if (mask & KADM5_POLICY)
442 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
449 kadm5_delete_principal(void *server_handle, krb5_principal principal)
452 kadm5_policy_ent_rec polent;
454 osa_princ_ent_rec adb;
455 kadm5_server_handle_t handle = server_handle;
457 CHECK_HANDLE(server_handle);
459 krb5_clear_error_message(handle->context);
461 if (principal == NULL)
464 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
467 if ((adb.aux_attributes & KADM5_POLICY)) {
468 if ((ret = kadm5_get_policy(handle->lhandle,
469 adb.policy, &polent))
471 polent.policy_refcnt--;
472 if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent,
475 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
476 kdb_free_entry(handle, &kdb, &adb);
480 if ((ret = kadm5_free_policy_ent(handle->lhandle, &polent))) {
481 kdb_free_entry(handle, &kdb, &adb);
486 ret = kdb_delete_entry(handle, principal);
488 kdb_free_entry(handle, &kdb, &adb);
494 kadm5_modify_principal(void *server_handle,
495 kadm5_principal_ent_t entry, long mask)
498 kadm5_policy_ent_rec npol, opol;
499 int have_npol = 0, have_opol = 0;
501 krb5_tl_data *tl_data_orig;
502 osa_princ_ent_rec adb;
503 kadm5_server_handle_t handle = server_handle;
505 CHECK_HANDLE(server_handle);
507 krb5_clear_error_message(handle->context);
509 if((mask & KADM5_PRINCIPAL) || (mask & KADM5_LAST_PWD_CHANGE) ||
510 (mask & KADM5_MOD_TIME) || (mask & KADM5_MOD_NAME) ||
511 (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) ||
512 (mask & KADM5_KEY_DATA) || (mask & KADM5_LAST_SUCCESS) ||
513 (mask & KADM5_LAST_FAILED))
514 return KADM5_BAD_MASK;
515 if((mask & ~ALL_PRINC_MASK))
516 return KADM5_BAD_MASK;
517 if((mask & KADM5_POLICY) && (mask & KADM5_POLICY_CLR))
518 return KADM5_BAD_MASK;
519 if(entry == (kadm5_principal_ent_t) NULL)
521 if (mask & KADM5_TL_DATA) {
522 tl_data_orig = entry->tl_data;
523 while (tl_data_orig) {
524 if (tl_data_orig->tl_data_type < 256)
525 return KADM5_BAD_TL_TYPE;
526 tl_data_orig = tl_data_orig->tl_data_next;
530 ret = kdb_get_entry(handle, entry->principal, &kdb, &adb);
535 * This is pretty much the same as create ...
538 if ((mask & KADM5_POLICY)) {
539 /* get the new policy */
540 ret = kadm5_get_policy(handle->lhandle, entry->policy, &npol);
544 ret = KADM5_BAD_POLICY;
546 case KADM5_UNK_POLICY:
547 case KADM5_BAD_POLICY:
548 ret = KADM5_UNK_POLICY;
555 /* if we already have a policy, get it to decrement the refcnt */
556 if(adb.aux_attributes & KADM5_POLICY) {
557 /* ... but not if the old and new are the same */
558 if(strcmp(adb.policy, entry->policy)) {
559 ret = kadm5_get_policy(handle->lhandle,
563 case KADM5_BAD_POLICY:
564 case KADM5_UNK_POLICY:
568 opol.policy_refcnt--;
574 npol.policy_refcnt++;
576 } else npol.policy_refcnt++;
578 /* set us up to use the new policy */
579 adb.aux_attributes |= KADM5_POLICY;
582 adb.policy = strdup(entry->policy);
584 /* set pw_max_life based on new policy */
585 if (npol.pw_max_life) {
586 ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb,
587 &(kdb.pw_expiration));
590 kdb.pw_expiration += npol.pw_max_life;
592 kdb.pw_expiration = 0;
596 if ((mask & KADM5_POLICY_CLR) &&
597 (adb.aux_attributes & KADM5_POLICY)) {
598 ret = kadm5_get_policy(handle->lhandle, adb.policy, &opol);
601 case KADM5_BAD_POLICY:
602 case KADM5_UNK_POLICY:
611 adb.aux_attributes &= ~KADM5_POLICY;
612 kdb.pw_expiration = 0;
613 opol.policy_refcnt--;
621 if (((mask & KADM5_POLICY) || (mask & KADM5_POLICY_CLR)) &&
624 kadm5_modify_policy_internal(handle->lhandle, &opol,
625 KADM5_REF_COUNT))) ||
628 kadm5_modify_policy_internal(handle->lhandle, &npol,
632 if ((mask & KADM5_ATTRIBUTES))
633 kdb.attributes = entry->attributes;
634 if ((mask & KADM5_MAX_LIFE))
635 kdb.max_life = entry->max_life;
636 if ((mask & KADM5_PRINC_EXPIRE_TIME))
637 kdb.expiration = entry->princ_expire_time;
638 if (mask & KADM5_PW_EXPIRATION)
639 kdb.pw_expiration = entry->pw_expiration;
640 if (mask & KADM5_MAX_RLIFE)
641 kdb.max_renewable_life = entry->max_renewable_life;
642 if (mask & KADM5_FAIL_AUTH_COUNT)
643 kdb.fail_auth_count = entry->fail_auth_count;
645 if((mask & KADM5_KVNO)) {
646 for (i = 0; i < kdb.n_key_data; i++)
647 kdb.key_data[i].key_data_kvno = entry->kvno;
650 if (mask & KADM5_TL_DATA) {
653 /* may have to change the version number of the API. Updates the list with the given tl_data rather than over-writting */
655 for (tl = entry->tl_data; tl;
656 tl = tl->tl_data_next)
658 ret = krb5_dbe_update_tl_data(handle->context, &kdb, tl);
666 /* let the mask propagate to the database provider */
669 ret = kdb_put_entry(handle, &kdb, &adb);
675 ret2 = kadm5_free_policy_ent(handle->lhandle, &opol);
676 ret = ret ? ret : ret2;
679 ret2 = kadm5_free_policy_ent(handle->lhandle, &npol);
680 ret = ret ? ret : ret2;
682 kdb_free_entry(handle, &kdb, &adb);
687 kadm5_rename_principal(void *server_handle,
688 krb5_principal source, krb5_principal target)
691 osa_princ_ent_rec adb;
693 kadm5_server_handle_t handle = server_handle;
695 CHECK_HANDLE(server_handle);
697 krb5_clear_error_message(handle->context);
699 if (source == NULL || target == NULL)
702 if ((ret = kdb_get_entry(handle, target, &kdb, &adb)) == 0) {
703 kdb_free_entry(handle, &kdb, &adb);
707 if ((ret = kdb_get_entry(handle, source, &kdb, &adb)))
710 /* this is kinda gross, but unavoidable */
712 for (i=0; i<kdb.n_key_data; i++) {
713 if ((kdb.key_data[i].key_data_ver == 1) ||
714 (kdb.key_data[i].key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL)) {
715 ret = KADM5_NO_RENAME_SALT;
720 kadm5_free_principal(handle->context, kdb.princ);
721 ret = kadm5_copy_principal(handle->context, target, &kdb.princ);
723 kdb.princ = NULL; /* so freeing the dbe doesn't lose */
727 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
730 ret = kdb_delete_entry(handle, source);
733 kdb_free_entry(handle, &kdb, &adb);
738 kadm5_get_principal(void *server_handle, krb5_principal principal,
739 kadm5_principal_ent_t entry,
743 osa_princ_ent_rec adb;
744 krb5_error_code ret = 0;
747 kadm5_server_handle_t handle = server_handle;
748 kadm5_principal_ent_rec entry_local, *entry_orig;
750 CHECK_HANDLE(server_handle);
752 krb5_clear_error_message(handle->context);
755 * In version 1, all the defined fields are always returned.
756 * entry is a pointer to a kadm5_principal_ent_t_v1 that should be
757 * filled with allocated memory.
759 if (handle->api_version == KADM5_API_VERSION_1) {
760 mask = KADM5_PRINCIPAL_NORMAL_MASK;
762 entry = &entry_local;
767 memset((char *) entry, 0, sizeof(*entry));
769 if (principal == NULL)
772 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
775 if ((mask & KADM5_POLICY) &&
776 adb.policy && (adb.aux_attributes & KADM5_POLICY)) {
777 if ((entry->policy = strdup(adb.policy)) == NULL) {
783 if (mask & KADM5_AUX_ATTRIBUTES)
784 entry->aux_attributes = adb.aux_attributes;
786 if ((mask & KADM5_PRINCIPAL) &&
787 (ret = krb5_copy_principal(handle->context, kdb.princ,
788 &entry->principal))) {
792 if (mask & KADM5_PRINC_EXPIRE_TIME)
793 entry->princ_expire_time = kdb.expiration;
795 if ((mask & KADM5_LAST_PWD_CHANGE) &&
796 (ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb,
797 &(entry->last_pwd_change)))) {
801 if (mask & KADM5_PW_EXPIRATION)
802 entry->pw_expiration = kdb.pw_expiration;
803 if (mask & KADM5_MAX_LIFE)
804 entry->max_life = kdb.max_life;
806 /* this is a little non-sensical because the function returns two */
807 /* values that must be checked separately against the mask */
808 if ((mask & KADM5_MOD_NAME) || (mask & KADM5_MOD_TIME)) {
809 ret = krb5_dbe_lookup_mod_princ_data(handle->context, &kdb,
816 if (! (mask & KADM5_MOD_TIME))
818 if (! (mask & KADM5_MOD_NAME)) {
819 krb5_free_principal(handle->context, entry->principal);
820 entry->principal = NULL;
824 if (mask & KADM5_ATTRIBUTES)
825 entry->attributes = kdb.attributes;
827 if (mask & KADM5_KVNO)
828 for (entry->kvno = 0, i=0; i<kdb.n_key_data; i++)
829 if (kdb.key_data[i].key_data_kvno > entry->kvno)
830 entry->kvno = kdb.key_data[i].key_data_kvno;
832 ret = krb5_dbe_lookup_mkvno(handle->context, &kdb, &entry->mkvno);
837 * It's my understanding that KADM5_API_VERSION_1 is for OpenVision admin
838 * system compatiblity and is not required to maintain at this point so I'm
839 * commenting out this code.
842 #if 0 /************** Begin IFDEF'ed OUT *******************************/
843 if (handle->api_version == KADM5_API_VERSION_2)
846 /* XXX I'll be damned if I know how to deal with this one --marc */
849 #endif /**************** END IFDEF'ed OUT *******************************/
852 * The new fields that only exist in version 2 start here
854 if (handle->api_version == KADM5_API_VERSION_2) {
855 if (mask & KADM5_MAX_RLIFE)
856 entry->max_renewable_life = kdb.max_renewable_life;
857 if (mask & KADM5_LAST_SUCCESS)
858 entry->last_success = kdb.last_success;
859 if (mask & KADM5_LAST_FAILED)
860 entry->last_failed = kdb.last_failed;
861 if (mask & KADM5_FAIL_AUTH_COUNT)
862 entry->fail_auth_count = kdb.fail_auth_count;
863 if (mask & KADM5_TL_DATA) {
864 krb5_tl_data *tl, *tl2;
866 entry->tl_data = NULL;
870 if (tl->tl_data_type > 255) {
871 if ((tl2 = dup_tl_data(tl)) == NULL) {
875 tl2->tl_data_next = entry->tl_data;
876 entry->tl_data = tl2;
880 tl = tl->tl_data_next;
883 if (mask & KADM5_KEY_DATA) {
884 entry->n_key_data = kdb.n_key_data;
885 if(entry->n_key_data) {
886 entry->key_data = (krb5_key_data *)
887 malloc(entry->n_key_data*sizeof(krb5_key_data));
888 if (entry->key_data == NULL) {
893 entry->key_data = NULL;
895 for (i = 0; i < entry->n_key_data; i++)
896 ret = krb5_copy_key_data_contents(handle->context,
898 &entry->key_data[i]);
905 * If KADM5_API_VERSION_1, we return an allocated structure, and
906 * we need to convert the new structure back into the format the
907 * caller is expecting.
909 if (handle->api_version == KADM5_API_VERSION_1) {
910 kadm5_principal_ent_t_v1 newv1;
912 newv1 = ((kadm5_principal_ent_t_v1) calloc(1, sizeof(*newv1)));
918 newv1->principal = entry->principal;
919 newv1->princ_expire_time = entry->princ_expire_time;
920 newv1->last_pwd_change = entry->last_pwd_change;
921 newv1->pw_expiration = entry->pw_expiration;
922 newv1->max_life = entry->max_life;
923 newv1->mod_name = entry->mod_name;
924 newv1->mod_date = entry->mod_date;
925 newv1->attributes = entry->attributes;
926 newv1->kvno = entry->kvno;
927 newv1->mkvno = entry->mkvno;
928 newv1->policy = entry->policy;
929 newv1->aux_attributes = entry->aux_attributes;
931 *((kadm5_principal_ent_t_v1 *) entry_orig) = newv1;
937 if (ret && entry->principal)
938 krb5_free_principal(handle->context, entry->principal);
939 kdb_free_entry(handle, &kdb, &adb);
945 * Function: check_pw_reuse
947 * Purpose: Check if a key appears in a list of keys, in order to
948 * enforce password history.
952 * context (r) the krb5 context
953 * hist_keyblock (r) the key that hist_key_data is
955 * n_new_key_data (r) length of new_key_data
956 * new_key_data (r) keys to check against
957 * pw_hist_data, encrypted in hist_keyblock
958 * n_pw_hist_data (r) length of pw_hist_data
959 * pw_hist_data (r) passwords to check new_key_data against
962 * For each new_key in new_key_data:
963 * decrypt new_key with the master_keyblock
964 * for each password in pw_hist_data:
965 * for each hist_key in password:
966 * decrypt hist_key with hist_keyblock
967 * compare the new_key and hist_key
969 * Returns krb5 errors, KADM5_PASS_RESUSE if a key in
970 * new_key_data is the same as a key in pw_hist_data, or 0.
973 check_pw_reuse(krb5_context context,
975 krb5_keyblock *hist_keyblock,
976 int n_new_key_data, krb5_key_data *new_key_data,
977 unsigned int n_pw_hist_data, osa_pw_hist_ent *pw_hist_data)
980 krb5_keyblock newkey, histkey;
983 for (x = 0; x < n_new_key_data; x++) {
984 ret = krb5_dbekd_decrypt_key_data(context,
990 for (y = 0; y < n_pw_hist_data; y++) {
991 for (z = 0; z < pw_hist_data[y].n_key_data; z++) {
992 ret = krb5_dbekd_decrypt_key_data(context,
994 &pw_hist_data[y].key_data[z],
999 if ((newkey.length == histkey.length) &&
1000 (newkey.enctype == histkey.enctype) &&
1001 (memcmp(newkey.contents, histkey.contents,
1002 histkey.length) == 0)) {
1003 krb5_free_keyblock_contents(context, &histkey);
1004 krb5_free_keyblock_contents(context, &newkey);
1006 return(KADM5_PASS_REUSE);
1008 krb5_free_keyblock_contents(context, &histkey);
1011 krb5_free_keyblock_contents(context, &newkey);
1018 * Function: create_history_entry
1020 * Purpose: Creates a password history entry from an array of
1025 * context (r) krb5_context to use
1026 * n_key_data (r) number of elements in key_data
1027 * key_data (r) keys to add to the history entry
1028 * hist (w) history entry to fill in
1032 * hist->key_data is allocated to store n_key_data key_datas. Each
1033 * element of key_data is decrypted with master_keyblock, re-encrypted
1034 * in hist_key, and added to hist->key_data. hist->n_key_data is
1035 * set to n_key_data.
1038 int create_history_entry(krb5_context context, krb5_keyblock *mkey, int n_key_data,
1039 krb5_key_data *key_data, osa_pw_hist_ent *hist)
1045 hist->key_data = (krb5_key_data*)malloc(n_key_data*sizeof(krb5_key_data));
1046 if (hist->key_data == NULL)
1048 memset(hist->key_data, 0, n_key_data*sizeof(krb5_key_data));
1050 for (i = 0; i < n_key_data; i++) {
1051 ret = krb5_dbekd_decrypt_key_data(context,
1058 ret = krb5_dbekd_encrypt_key_data(context, &hist_key,
1060 key_data[i].key_data_kvno,
1061 &hist->key_data[i]);
1065 krb5_free_keyblock_contents(context, &key);
1066 /* krb5_free_keysalt(context, &salt); */
1069 hist->n_key_data = n_key_data;
1074 void free_history_entry(krb5_context context, osa_pw_hist_ent *hist)
1078 for (i = 0; i < hist->n_key_data; i++)
1079 krb5_free_key_data_contents(context, &hist->key_data[i]);
1080 free(hist->key_data);
1084 * Function: add_to_history
1086 * Purpose: Adds a password to a principal's password history.
1090 * context (r) krb5_context to use
1091 * adb (r/w) admin principal entry to add keys to
1092 * pol (r) adb's policy
1093 * pw (r) keys for the password to add to adb's key history
1097 * add_to_history adds a single password to adb's password history.
1098 * pw contains n_key_data keys in its key_data, in storage should be
1099 * allocated but not freed by the caller (XXX blech!).
1101 * This function maintains adb->old_keys as a circular queue. It
1102 * starts empty, and grows each time this function is called until it
1103 * is pol->pw_history_num items long. adb->old_key_len holds the
1104 * number of allocated entries in the array, and must therefore be [0,
1105 * pol->pw_history_num). adb->old_key_next is the index into the
1106 * array where the next element should be written, and must be [0,
1107 * adb->old_key_len).
1109 static kadm5_ret_t add_to_history(krb5_context context,
1110 osa_princ_ent_t adb,
1111 kadm5_policy_ent_t pol,
1112 osa_pw_hist_ent *pw)
1114 osa_pw_hist_ent *histp;
1116 unsigned int i, knext, nkeys;
1118 nhist = pol->pw_history_num;
1119 /* A history of 1 means just check the current password */
1123 nkeys = adb->old_key_len;
1124 knext = adb->old_key_next;
1125 /* resize the adb->old_keys array if necessary */
1126 if (nkeys + 1 < nhist) {
1127 if (adb->old_keys == NULL) {
1128 adb->old_keys = (osa_pw_hist_ent *)
1129 malloc((nkeys + 1) * sizeof (osa_pw_hist_ent));
1131 adb->old_keys = (osa_pw_hist_ent *)
1132 realloc(adb->old_keys,
1133 (nkeys + 1) * sizeof (osa_pw_hist_ent));
1135 if (adb->old_keys == NULL)
1138 memset(&adb->old_keys[nkeys], 0, sizeof(osa_pw_hist_ent));
1139 nkeys = ++adb->old_key_len;
1141 * To avoid losing old keys, shift forward each entry after
1144 for (i = nkeys - 1; i > knext; i--) {
1145 adb->old_keys[i] = adb->old_keys[i - 1];
1147 memset(&adb->old_keys[knext], 0, sizeof(osa_pw_hist_ent));
1148 } else if (nkeys + 1 > nhist) {
1150 * The policy must have changed! Shrink the array.
1151 * Can't simply realloc() down, since it might be wrapped.
1152 * To understand the arithmetic below, note that we are
1153 * copying into new positions 0 .. N-1 from old positions
1154 * old_key_next-N .. old_key_next-1, modulo old_key_len,
1155 * where N = pw_history_num - 1 is the length of the
1156 * shortened list. Matt Crawford, FNAL
1159 * M = adb->old_key_len, N = pol->pw_history_num - 1
1161 * tmp[0] .. tmp[N-1] = old[(knext-N)%M] .. old[(knext-1)%M]
1166 tmp = (osa_pw_hist_ent *)
1167 malloc((nhist - 1) * sizeof (osa_pw_hist_ent));
1170 for (i = 0; i < nhist - 1; i++) {
1172 * Add nkeys once before taking remainder to avoid
1175 j = (i + nkeys + knext - (nhist - 1)) % nkeys;
1176 tmp[i] = adb->old_keys[j];
1178 /* Now free the ones we don't keep (the oldest ones) */
1179 for (i = 0; i < nkeys - (nhist - 1); i++) {
1180 j = (i + nkeys + knext) % nkeys;
1181 histp = &adb->old_keys[j];
1182 for (j = 0; j < histp->n_key_data; j++) {
1183 krb5_free_key_data_contents(context, &histp->key_data[j]);
1185 free(histp->key_data);
1187 free((void *)adb->old_keys);
1188 adb->old_keys = tmp;
1189 nkeys = adb->old_key_len = nhist - 1;
1190 knext = adb->old_key_next = 0;
1194 * If nhist decreased since the last password change, and nkeys+1
1195 * is less than the previous nhist, it is possible for knext to
1196 * index into unallocated space. This condition would not be
1197 * caught by the resizing code above.
1199 if (knext + 1 > nkeys)
1200 knext = adb->old_key_next = 0;
1201 /* free the old pw history entry if it contains data */
1202 histp = &adb->old_keys[knext];
1203 for (i = 0; i < histp->n_key_data; i++)
1204 krb5_free_key_data_contents(context, &histp->key_data[i]);
1205 free(histp->key_data);
1207 /* store the new entry */
1208 adb->old_keys[knext] = *pw;
1210 /* update the next pointer */
1211 if (++adb->old_key_next == nhist - 1)
1212 adb->old_key_next = 0;
1217 /* FIXME: don't use global variable for this */
1218 krb5_boolean use_password_server = 0;
1220 #ifdef USE_PASSWORD_SERVER
1222 kadm5_use_password_server (void)
1224 return use_password_server;
1229 kadm5_set_use_password_server (void)
1231 use_password_server = 1;
1234 #ifdef USE_PASSWORD_SERVER
1237 * kadm5_launch_task () runs a program (task_path) to synchronize the
1238 * Apple password server with the Kerberos database. Password server
1239 * programs can receive arguments on the command line (task_argv)
1240 * and a block of data via stdin (data_buffer).
1242 * Because a failure to communicate with the tool results in the
1243 * password server falling out of sync with the database,
1244 * kadm5_launch_task() always fails if it can't talk to the tool.
1248 kadm5_launch_task (krb5_context context,
1249 const char *task_path, char * const task_argv[],
1255 ret = pipe (data_pipe);
1260 pid_t pid = fork ();
1263 close (data_pipe[0]);
1264 close (data_pipe[1]);
1265 } else if (pid == 0) {
1268 if (dup2 (data_pipe[0], STDIN_FILENO) == -1)
1271 close (data_pipe[0]);
1272 close (data_pipe[1]);
1274 execv (task_path, task_argv);
1276 _exit (1); /* Fail if execv fails */
1283 close (data_pipe[0]);
1285 /* Write out the buffer to the child, add \n */
1287 if (krb5_net_write (context, data_pipe[1], buffer, strlen (buffer)) < 0
1288 || krb5_net_write (context, data_pipe[1], "\n", 1) < 0)
1290 /* kill the child to make sure waitpid() won't hang later */
1292 kill (pid, SIGKILL);
1295 close (data_pipe[1]);
1297 waitpid (pid, &status, 0);
1300 if (WIFEXITED (status)) {
1301 /* child read password and exited. Check the return value. */
1302 if ((WEXITSTATUS (status) != 0) && (WEXITSTATUS (status) != 252)) {
1303 ret = KRB5KDC_ERR_POLICY; /* password change rejected */
1306 /* child read password but crashed or was killed */
1307 ret = KRB5KRB_ERR_GENERIC; /* FIXME: better error */
1319 kadm5_chpass_principal(void *server_handle,
1320 krb5_principal principal, char *password)
1323 kadm5_chpass_principal_3(server_handle, principal, FALSE,
1328 kadm5_chpass_principal_3(void *server_handle,
1329 krb5_principal principal, krb5_boolean keepold,
1330 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1334 kadm5_policy_ent_rec pol;
1335 osa_princ_ent_rec adb;
1336 krb5_db_entry kdb, kdb_save;
1337 int ret, ret2, last_pwd, hist_added;
1339 kadm5_server_handle_t handle = server_handle;
1340 osa_pw_hist_ent hist;
1341 krb5_keyblock *act_mkey;
1344 CHECK_HANDLE(server_handle);
1346 krb5_clear_error_message(handle->context);
1349 memset(&hist, 0, sizeof(hist));
1351 if (principal == NULL || password == NULL)
1353 if ((krb5_principal_compare(handle->context,
1354 principal, hist_princ)) == TRUE)
1355 return KADM5_PROTECT_PRINCIPAL;
1357 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1360 /* we are going to need the current keys after the new keys are set */
1361 if ((ret = kdb_get_entry(handle, principal, &kdb_save, NULL))) {
1362 kdb_free_entry(handle, &kdb, &adb);
1366 if ((adb.aux_attributes & KADM5_POLICY)) {
1367 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &pol)))
1372 if ((ret = passwd_check(handle, password, adb.aux_attributes &
1373 KADM5_POLICY, &pol, principal)))
1376 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
1377 active_mkey_list, &act_kvno, &act_mkey);
1381 ret = krb5_dbe_cpw(handle->context, act_mkey,
1382 n_ks_tuple?ks_tuple:handle->params.keysalts,
1383 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
1384 password, 0 /* increment kvno */,
1389 ret = krb5_dbe_update_mkvno(handle->context, &kdb, act_kvno);
1393 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1395 ret = krb5_timeofday(handle->context, &now);
1399 if ((adb.aux_attributes & KADM5_POLICY)) {
1400 /* the policy was loaded before */
1402 ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1409 * The spec says this check is overridden if the caller has
1410 * modify privilege. The admin server therefore makes this
1411 * check itself (in chpass_principal_wrapper, misc.c). A
1412 * local caller implicitly has all authorization bits.
1414 if ((now - last_pwd) < pol.pw_min_life &&
1415 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1416 ret = KADM5_PASS_TOOSOON;
1421 ret = create_history_entry(handle->context,
1423 kdb_save.n_key_data,
1424 kdb_save.key_data, &hist);
1428 ret = check_pw_reuse(handle->context, act_mkey, &hist_key,
1429 kdb.n_key_data, kdb.key_data,
1434 if (pol.pw_history_num > 1) {
1435 if (adb.admin_history_kvno != hist_kvno) {
1436 ret = KADM5_BAD_HIST_KEY;
1440 ret = check_pw_reuse(handle->context, act_mkey, &hist_key,
1441 kdb.n_key_data, kdb.key_data,
1442 adb.old_key_len, adb.old_keys);
1446 ret = add_to_history(handle->context, &adb, &pol, &hist);
1452 if (pol.pw_max_life)
1453 kdb.pw_expiration = now + pol.pw_max_life;
1455 kdb.pw_expiration = 0;
1457 kdb.pw_expiration = 0;
1460 #ifdef USE_PASSWORD_SERVER
1461 if (kadm5_use_password_server () &&
1462 (krb5_princ_size (handle->context, principal) == 1)) {
1463 krb5_data *princ = krb5_princ_component (handle->context, principal, 0);
1464 const char *path = "/usr/sbin/mkpassdb";
1465 char *argv[] = { "mkpassdb", "-setpassword", NULL, NULL };
1466 char *pstring = NULL;
1469 pstring = malloc ((princ->length + 1) * sizeof (char));
1470 if (pstring == NULL) { ret = ENOMEM; }
1474 memcpy (pstring, princ->data, princ->length);
1475 pstring [princ->length] = '\0';
1478 ret = kadm5_launch_task (handle->context, path, argv, password);
1481 if (pstring != NULL)
1489 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
1493 /* key data and attributes changed, let the database provider know */
1494 kdb.mask = KADM5_KEY_DATA | KADM5_ATTRIBUTES /* | KADM5_CPW_FUNCTION */;
1496 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1501 if (!hist_added && hist.key_data)
1502 free_history_entry(handle->context, &hist);
1503 kdb_free_entry(handle, &kdb, &adb);
1504 kdb_free_entry(handle, &kdb_save, NULL);
1505 krb5_db_free_principal(handle->context, &kdb, 1);
1507 if (have_pol && (ret2 = kadm5_free_policy_ent(handle->lhandle, &pol))
1515 kadm5_randkey_principal(void *server_handle,
1516 krb5_principal principal,
1517 krb5_keyblock **keyblocks,
1521 kadm5_randkey_principal_3(server_handle, principal,
1526 kadm5_randkey_principal_3(void *server_handle,
1527 krb5_principal principal,
1528 krb5_boolean keepold,
1529 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1530 krb5_keyblock **keyblocks,
1534 osa_princ_ent_rec adb;
1536 kadm5_policy_ent_rec pol;
1537 krb5_key_data *key_data;
1538 int ret, last_pwd, have_pol = 0;
1539 kadm5_server_handle_t handle = server_handle;
1540 krb5_keyblock *act_mkey;
1545 CHECK_HANDLE(server_handle);
1547 krb5_clear_error_message(handle->context);
1549 if (principal == NULL)
1551 if (hist_princ && /* this will be NULL when initializing the databse */
1552 ((krb5_principal_compare(handle->context,
1553 principal, hist_princ)) == TRUE))
1554 return KADM5_PROTECT_PRINCIPAL;
1556 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1559 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
1560 active_mkey_list, NULL, &act_mkey);
1564 ret = krb5_dbe_crk(handle->context, act_mkey,
1565 n_ks_tuple?ks_tuple:handle->params.keysalts,
1566 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
1572 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1574 ret = krb5_timeofday(handle->context, &now);
1578 if ((adb.aux_attributes & KADM5_POLICY)) {
1579 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1584 ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1591 * The spec says this check is overridden if the caller has
1592 * modify privilege. The admin server therefore makes this
1593 * check itself (in chpass_principal_wrapper, misc.c). A
1594 * local caller implicitly has all authorization bits.
1596 if((now - last_pwd) < pol.pw_min_life &&
1597 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1598 ret = KADM5_PASS_TOOSOON;
1603 if(pol.pw_history_num > 1) {
1604 if(adb.admin_history_kvno != hist_kvno) {
1605 ret = KADM5_BAD_HIST_KEY;
1609 ret = check_pw_reuse(handle->context, act_mkey, &hist_key,
1610 kdb.n_key_data, kdb.key_data,
1611 adb.old_key_len, adb.old_keys);
1615 if (pol.pw_max_life)
1616 kdb.pw_expiration = now + pol.pw_max_life;
1618 kdb.pw_expiration = 0;
1620 kdb.pw_expiration = 0;
1623 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
1628 if (handle->api_version == KADM5_API_VERSION_1) {
1629 /* Version 1 clients will expect to see a DES_CRC enctype. */
1630 ret = krb5_dbe_find_enctype(handle->context, &kdb,
1631 ENCTYPE_DES_CBC_CRC,
1636 ret = decrypt_key_data(handle->context, act_mkey, 1, key_data,
1641 ret = decrypt_key_data(handle->context, act_mkey,
1642 kdb.n_key_data, kdb.key_data,
1649 /* key data changed, let the database provider know */
1650 kdb.mask = KADM5_KEY_DATA /* | KADM5_RANDKEY_USED */;
1652 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1657 kdb_free_entry(handle, &kdb, &adb);
1659 kadm5_free_policy_ent(handle->lhandle, &pol);
1665 * kadm5_setv4key_principal:
1667 * Set only ONE key of the principal, removing all others. This key
1668 * must have the DES_CBC_CRC enctype and is entered as having the
1669 * krb4 salttype. This is to enable things like kadmind4 to work.
1672 kadm5_setv4key_principal(void *server_handle,
1673 krb5_principal principal,
1674 krb5_keyblock *keyblock)
1677 osa_princ_ent_rec adb;
1679 kadm5_policy_ent_rec pol;
1680 krb5_keysalt keysalt;
1681 int i, k, kvno, ret, have_pol = 0;
1685 kadm5_server_handle_t handle = server_handle;
1686 krb5_key_data tmp_key_data;
1687 krb5_keyblock *act_mkey;
1689 memset( &tmp_key_data, 0, sizeof(tmp_key_data));
1691 CHECK_HANDLE(server_handle);
1693 krb5_clear_error_message(handle->context);
1695 if (principal == NULL || keyblock == NULL)
1697 if (hist_princ && /* this will be NULL when initializing the databse */
1698 ((krb5_principal_compare(handle->context,
1699 principal, hist_princ)) == TRUE))
1700 return KADM5_PROTECT_PRINCIPAL;
1702 if (keyblock->enctype != ENCTYPE_DES_CBC_CRC)
1703 return KADM5_SETV4KEY_INVAL_ENCTYPE;
1705 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1708 for (kvno = 0, i=0; i<kdb.n_key_data; i++)
1709 if (kdb.key_data[i].key_data_kvno > kvno)
1710 kvno = kdb.key_data[i].key_data_kvno;
1712 if (kdb.key_data != NULL)
1713 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
1715 kdb.key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, sizeof(krb5_key_data));
1716 if (kdb.key_data == NULL)
1718 memset(kdb.key_data, 0, sizeof(krb5_key_data));
1720 keysalt.type = KRB5_KDB_SALTTYPE_V4;
1721 /* XXX data.magic? */
1722 keysalt.data.length = 0;
1723 keysalt.data.data = NULL;
1725 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
1726 active_mkey_list, NULL, &act_mkey);
1730 /* use tmp_key_data as temporary location and reallocate later */
1731 ret = krb5_dbekd_encrypt_key_data(handle->context, act_mkey,
1732 keyblock, &keysalt, kvno + 1,
1738 for (k = 0; k < tmp_key_data.key_data_ver; k++) {
1739 kdb.key_data->key_data_type[k] = tmp_key_data.key_data_type[k];
1740 kdb.key_data->key_data_length[k] = tmp_key_data.key_data_length[k];
1741 if (tmp_key_data.key_data_contents[k]) {
1742 kdb.key_data->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]);
1743 if (kdb.key_data->key_data_contents[k] == NULL) {
1744 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
1745 kdb.key_data = NULL;
1750 memcpy (kdb.key_data->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
1752 memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
1753 free (tmp_key_data.key_data_contents[k]);
1754 tmp_key_data.key_data_contents[k] = NULL;
1760 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1762 ret = krb5_timeofday(handle->context, &now);
1766 if ((adb.aux_attributes & KADM5_POLICY)) {
1767 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1774 * The spec says this check is overridden if the caller has
1775 * modify privilege. The admin server therefore makes this
1776 * check itself (in chpass_principal_wrapper, misc.c). A
1777 * local caller implicitly has all authorization bits.
1779 if (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1782 if((now - last_pwd) < pol.pw_min_life &&
1783 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1784 ret = KADM5_PASS_TOOSOON;
1790 * Should we be checking/updating pw history here?
1792 if(pol.pw_history_num > 1) {
1793 if(adb.admin_history_kvno != hist_kvno) {
1794 ret = KADM5_BAD_HIST_KEY;
1798 if (ret = check_pw_reuse(handle->context,
1800 kdb.n_key_data, kdb.key_data,
1801 adb.old_key_len, adb.old_keys))
1806 if (pol.pw_max_life)
1807 kdb.pw_expiration = now + pol.pw_max_life;
1809 kdb.pw_expiration = 0;
1811 kdb.pw_expiration = 0;
1814 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
1818 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1823 for (i = 0; i < tmp_key_data.key_data_ver; i++) {
1824 if (tmp_key_data.key_data_contents[i]) {
1825 memset (tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]);
1826 free (tmp_key_data.key_data_contents[i]);
1830 kdb_free_entry(handle, &kdb, &adb);
1832 kadm5_free_policy_ent(handle->lhandle, &pol);
1838 kadm5_setkey_principal(void *server_handle,
1839 krb5_principal principal,
1840 krb5_keyblock *keyblocks,
1844 kadm5_setkey_principal_3(server_handle, principal,
1850 kadm5_setkey_principal_3(void *server_handle,
1851 krb5_principal principal,
1852 krb5_boolean keepold,
1853 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1854 krb5_keyblock *keyblocks,
1858 osa_princ_ent_rec adb;
1860 kadm5_policy_ent_rec pol;
1861 krb5_key_data *old_key_data;
1863 int i, j, k, kvno, ret, have_pol = 0;
1867 kadm5_server_handle_t handle = server_handle;
1868 krb5_boolean similar;
1869 krb5_keysalt keysalt;
1870 krb5_key_data tmp_key_data;
1871 krb5_key_data *tptr;
1872 krb5_keyblock *act_mkey;
1874 CHECK_HANDLE(server_handle);
1876 krb5_clear_error_message(handle->context);
1878 if (principal == NULL || keyblocks == NULL)
1880 if (hist_princ && /* this will be NULL when initializing the databse */
1881 ((krb5_principal_compare(handle->context,
1882 principal, hist_princ)) == TRUE))
1883 return KADM5_PROTECT_PRINCIPAL;
1885 for (i = 0; i < n_keys; i++) {
1886 for (j = i+1; j < n_keys; j++) {
1887 if ((ret = krb5_c_enctype_compare(handle->context,
1888 keyblocks[i].enctype,
1889 keyblocks[j].enctype,
1894 if (ks_tuple[i].ks_salttype == ks_tuple[j].ks_salttype)
1895 return KADM5_SETKEY_DUP_ENCTYPES;
1897 return KADM5_SETKEY_DUP_ENCTYPES;
1902 if (n_ks_tuple && n_ks_tuple != n_keys)
1903 return KADM5_SETKEY3_ETYPE_MISMATCH;
1905 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1908 for (kvno = 0, i=0; i<kdb.n_key_data; i++)
1909 if (kdb.key_data[i].key_data_kvno > kvno)
1910 kvno = kdb.key_data[i].key_data_kvno;
1913 old_key_data = kdb.key_data;
1914 n_old_keys = kdb.n_key_data;
1916 if (kdb.key_data != NULL)
1917 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
1919 old_key_data = NULL;
1922 kdb.key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, (n_keys+n_old_keys)
1923 *sizeof(krb5_key_data));
1924 if (kdb.key_data == NULL) {
1929 memset(kdb.key_data, 0, (n_keys+n_old_keys)*sizeof(krb5_key_data));
1932 for (i = 0; i < n_keys; i++) {
1934 keysalt.type = ks_tuple[i].ks_salttype;
1935 keysalt.data.length = 0;
1936 keysalt.data.data = NULL;
1937 if (ks_tuple[i].ks_enctype != keyblocks[i].enctype) {
1938 ret = KADM5_SETKEY3_ETYPE_MISMATCH;
1942 memset (&tmp_key_data, 0, sizeof(tmp_key_data));
1944 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
1945 active_mkey_list, NULL, &act_mkey);
1949 ret = krb5_dbekd_encrypt_key_data(handle->context,
1952 n_ks_tuple ? &keysalt : NULL,
1958 tptr = &kdb.key_data[i];
1959 tptr->key_data_ver = tmp_key_data.key_data_ver;
1960 tptr->key_data_kvno = tmp_key_data.key_data_kvno;
1961 for (k = 0; k < tmp_key_data.key_data_ver; k++) {
1962 tptr->key_data_type[k] = tmp_key_data.key_data_type[k];
1963 tptr->key_data_length[k] = tmp_key_data.key_data_length[k];
1964 if (tmp_key_data.key_data_contents[k]) {
1965 tptr->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]);
1966 if (tptr->key_data_contents[k] == NULL) {
1968 for (i1 = k; i1 < tmp_key_data.key_data_ver; i1++) {
1969 if (tmp_key_data.key_data_contents[i1]) {
1970 memset (tmp_key_data.key_data_contents[i1], 0, tmp_key_data.key_data_length[i1]);
1971 free (tmp_key_data.key_data_contents[i1]);
1978 memcpy (tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
1980 memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
1981 free (tmp_key_data.key_data_contents[k]);
1982 tmp_key_data.key_data_contents[k] = NULL;
1988 /* copy old key data if necessary */
1989 for (i = 0; i < n_old_keys; i++) {
1990 kdb.key_data[i+n_keys] = old_key_data[i];
1991 memset(&old_key_data[i], 0, sizeof (krb5_key_data));
1996 krb5_db_free(handle->context, old_key_data);
1998 /* assert(kdb.n_key_data == n_keys + n_old_keys) */
1999 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
2001 if ((ret = krb5_timeofday(handle->context, &now)))
2004 if ((adb.aux_attributes & KADM5_POLICY)) {
2005 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
2012 * The spec says this check is overridden if the caller has
2013 * modify privilege. The admin server therefore makes this
2014 * check itself (in chpass_principal_wrapper, misc.c). A
2015 * local caller implicitly has all authorization bits.
2017 if (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
2020 if((now - last_pwd) < pol.pw_min_life &&
2021 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
2022 ret = KADM5_PASS_TOOSOON;
2028 * Should we be checking/updating pw history here?
2030 if (pol.pw_history_num > 1) {
2031 if(adb.admin_history_kvno != hist_kvno) {
2032 ret = KADM5_BAD_HIST_KEY;
2036 if (ret = check_pw_reuse(handle->context,
2038 kdb.n_key_data, kdb.key_data,
2039 adb.old_key_len, adb.old_keys))
2044 if (pol.pw_max_life)
2045 kdb.pw_expiration = now + pol.pw_max_life;
2047 kdb.pw_expiration = 0;
2049 kdb.pw_expiration = 0;
2052 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now)))
2055 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
2060 kdb_free_entry(handle, &kdb, &adb);
2062 kadm5_free_policy_ent(handle->lhandle, &pol);
2068 * Return the list of keys like kadm5_randkey_principal,
2069 * but don't modify the principal.
2072 kadm5_get_principal_keys(void *server_handle /* IN */,
2073 krb5_principal principal /* IN */,
2074 krb5_keyblock **keyblocks /* OUT */,
2075 int *n_keys /* OUT */)
2078 osa_princ_ent_rec adb;
2079 krb5_key_data *key_data;
2081 kadm5_server_handle_t handle = server_handle;
2082 krb5_keyblock *mkey_ptr;
2087 CHECK_HANDLE(server_handle);
2089 if (principal == NULL)
2092 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
2096 if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist, &kdb,
2098 krb5_keylist_node *tmp_mkey_list;
2099 /* try refreshing master key list */
2100 /* XXX it would nice if we had the mkvno here for optimization */
2101 if (krb5_db_fetch_mkey_list(handle->context, master_princ,
2102 &master_keyblock, 0,
2103 &tmp_mkey_list) == 0) {
2104 krb5_dbe_free_key_list(handle->context, master_keylist);
2105 master_keylist = tmp_mkey_list;
2106 if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist,
2107 &kdb, &mkey_ptr))) {
2115 if (handle->api_version == KADM5_API_VERSION_1) {
2116 /* Version 1 clients will expect to see a DES_CRC enctype. */
2117 if ((ret = krb5_dbe_find_enctype(handle->context, &kdb,
2118 ENCTYPE_DES_CBC_CRC,
2119 -1, -1, &key_data)))
2122 if ((ret = decrypt_key_data(handle->context, mkey_ptr, 1, key_data,
2126 ret = decrypt_key_data(handle->context, mkey_ptr,
2127 kdb.n_key_data, kdb.key_data,
2136 kdb_free_entry(handle, &kdb, &adb);
2143 * Allocate an array of n_key_data krb5_keyblocks, fill in each
2144 * element with the results of decrypting the nth key in key_data with
2145 * mkey, and if n_keys is not NULL fill it in with the
2146 * number of keys decrypted.
2148 static int decrypt_key_data(krb5_context context, krb5_keyblock *mkey,
2149 int n_key_data, krb5_key_data *key_data,
2150 krb5_keyblock **keyblocks, int *n_keys)
2152 krb5_keyblock *keys;
2155 keys = (krb5_keyblock *) malloc(n_key_data*sizeof(krb5_keyblock));
2158 memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock));
2160 for (i = 0; i < n_key_data; i++) {
2161 ret = krb5_dbekd_decrypt_key_data(context, mkey,
2165 for (; i >= 0; i--) {
2166 if (keys[i].contents) {
2167 memset (keys[i].contents, 0, keys[i].length);
2168 free( keys[i].contents );
2172 memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock));
2180 *n_keys = n_key_data;
2186 * Function: kadm5_decrypt_key
2188 * Purpose: Retrieves and decrypts a principal key.
2192 * server_handle (r) kadm5 handle
2193 * entry (r) principal retrieved with kadm5_get_principal
2194 * ktype (r) enctype to search for, or -1 to ignore
2195 * stype (r) salt type to search for, or -1 to ignore
2196 * kvno (r) kvno to search for, -1 for max, 0 for max
2197 * only if it also matches ktype and stype
2198 * keyblock (w) keyblock to fill in
2199 * keysalt (w) keysalt to fill in, or NULL
2200 * kvnop (w) kvno to fill in, or NULL
2202 * Effects: Searches the key_data array of entry, which must have been
2203 * retrived with kadm5_get_principal with the KADM5_KEY_DATA mask, to
2204 * find a key with a specified enctype, salt type, and kvno in a
2205 * principal entry. If not found, return ENOENT. Otherwise, decrypt
2206 * it with the master key, and return the key in keyblock, the salt
2207 * in salttype, and the key version number in kvno.
2209 * If ktype or stype is -1, it is ignored for the search. If kvno is
2210 * -1, ktype and stype are ignored and the key with the max kvno is
2211 * returned. If kvno is 0, only the key with the max kvno is returned
2212 * and only if it matches the ktype and stype; otherwise, ENOENT is
2215 kadm5_ret_t kadm5_decrypt_key(void *server_handle,
2216 kadm5_principal_ent_t entry, krb5_int32
2217 ktype, krb5_int32 stype, krb5_int32
2218 kvno, krb5_keyblock *keyblock,
2219 krb5_keysalt *keysalt, int *kvnop)
2221 kadm5_server_handle_t handle = server_handle;
2222 krb5_db_entry dbent;
2223 krb5_key_data *key_data;
2224 krb5_keyblock *mkey_ptr;
2227 CHECK_HANDLE(server_handle);
2229 if (entry->n_key_data == 0 || entry->key_data == NULL)
2232 /* find_enctype only uses these two fields */
2233 dbent.n_key_data = entry->n_key_data;
2234 dbent.key_data = entry->key_data;
2235 if ((ret = krb5_dbe_find_enctype(handle->context, &dbent, ktype,
2236 stype, kvno, &key_data)))
2239 /* find_mkey only uses this field */
2240 dbent.tl_data = entry->tl_data;
2241 if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist, &dbent,
2243 krb5_keylist_node *tmp_mkey_list;
2244 /* try refreshing master key list */
2245 /* XXX it would nice if we had the mkvno here for optimization */
2246 if (krb5_db_fetch_mkey_list(handle->context, master_princ,
2247 &master_keyblock, 0, &tmp_mkey_list) == 0) {
2248 krb5_dbe_free_key_list(handle->context, master_keylist);
2249 master_keylist = tmp_mkey_list;
2250 if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist,
2251 &dbent, &mkey_ptr))) {
2259 if ((ret = krb5_dbekd_decrypt_key_data(handle->context,
2261 keyblock, keysalt)))
2265 * Coerce the enctype of the output keyblock in case we got an
2266 * inexact match on the enctype; this behavior will go away when
2267 * the key storage architecture gets redesigned for 1.3.
2270 keyblock->enctype = ktype;
2273 *kvnop = key_data->key_data_kvno;