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 *tempprinc = *inprinc;
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;
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;
264 ret = passwd_check(handle, password, (mask & KADM5_POLICY),
265 &polent, entry->principal);
267 if (mask & KADM5_POLICY)
268 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
273 * Start populating the various DB fields, using the
274 * "defaults" for fields that were not specified by the
277 if ((ret = krb5_timeofday(handle->context, &now))) {
278 if (mask & KADM5_POLICY)
279 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
283 kdb.magic = KRB5_KDB_MAGIC_NUMBER;
284 kdb.len = KRB5_KDB_V1_BASE_LENGTH; /* gag me with a chainsaw */
286 if ((mask & KADM5_ATTRIBUTES))
287 kdb.attributes = entry->attributes;
289 kdb.attributes = handle->params.flags;
291 if ((mask & KADM5_MAX_LIFE))
292 kdb.max_life = entry->max_life;
294 kdb.max_life = handle->params.max_life;
296 if (mask & KADM5_MAX_RLIFE)
297 kdb.max_renewable_life = entry->max_renewable_life;
299 kdb.max_renewable_life = handle->params.max_rlife;
301 if ((mask & KADM5_PRINC_EXPIRE_TIME))
302 kdb.expiration = entry->princ_expire_time;
304 kdb.expiration = handle->params.expiration;
306 kdb.pw_expiration = 0;
307 if ((mask & KADM5_POLICY)) {
308 if(polent.pw_max_life)
309 kdb.pw_expiration = now + polent.pw_max_life;
311 kdb.pw_expiration = 0;
313 if ((mask & KADM5_PW_EXPIRATION))
314 kdb.pw_expiration = entry->pw_expiration;
316 kdb.last_success = 0;
318 kdb.fail_auth_count = 0;
320 /* this is kind of gross, but in order to free the tl data, I need
321 to free the entire kdb entry, and that will try to free the
324 if ((ret = kadm5_copy_principal(handle->context,
325 entry->principal, &(kdb.princ)))) {
326 if (mask & KADM5_POLICY)
327 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
331 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now))) {
332 krb5_db_free_principal(handle->context, &kdb, 1);
333 if (mask & KADM5_POLICY)
334 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
338 if (mask & KADM5_TL_DATA) {
339 /* splice entry->tl_data onto the front of kdb.tl_data */
340 tl_data_orig = kdb.tl_data;
341 for (tl_data_tail = entry->tl_data; tl_data_tail;
342 tl_data_tail = tl_data_tail->tl_data_next)
344 ret = krb5_dbe_update_tl_data(handle->context, &kdb, tl_data_tail);
347 krb5_db_free_principal(handle->context, &kdb, 1);
348 if (mask & KADM5_POLICY)
349 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
355 /* initialize the keys */
357 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
358 active_mkey_list, &act_kvno, &act_mkey);
360 krb5_db_free_principal(handle->context, &kdb, 1);
361 if (mask & KADM5_POLICY)
362 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
367 ret = krb5_dbe_cpw(handle->context, act_mkey,
368 n_ks_tuple?ks_tuple:handle->params.keysalts,
369 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
370 password, (mask & KADM5_KVNO)?entry->kvno:1,
373 /* Null password means create with random key (new in 1.8). */
374 ret = krb5_dbe_crk(handle->context, &master_keyblock,
375 n_ks_tuple?ks_tuple:handle->params.keysalts,
376 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
380 krb5_db_free_principal(handle->context, &kdb, 1);
381 if (mask & KADM5_POLICY)
382 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
386 /* Record the master key VNO used to encrypt this entry's keys */
387 ret = krb5_dbe_update_mkvno(handle->context, &kdb, act_kvno);
390 krb5_db_free_principal(handle->context, &kdb, 1);
391 if (mask & KADM5_POLICY)
392 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
396 /* populate the admin-server-specific fields. In the OV server,
397 this used to be in a separate database. Since there's already
398 marshalling code for the admin fields, to keep things simple,
399 I'm going to keep it, and make all the admin stuff occupy a
400 single tl_data record, */
402 adb.admin_history_kvno = hist_kvno;
403 if ((mask & KADM5_POLICY)) {
404 adb.aux_attributes = KADM5_POLICY;
406 /* this does *not* need to be strdup'ed, because adb is xdr */
407 /* encoded in osa_adb_create_princ, and not ever freed */
409 adb.policy = entry->policy;
412 /* increment the policy ref count, if any */
414 if ((mask & KADM5_POLICY)) {
415 polent.policy_refcnt++;
416 if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent,
419 krb5_db_free_principal(handle->context, &kdb, 1);
420 if (mask & KADM5_POLICY)
421 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
426 /* In all cases key and the principal data is set, let the database provider know */
427 kdb.mask = mask | KADM5_KEY_DATA | KADM5_PRINCIPAL ;
429 /* store the new db entry */
430 ret = kdb_put_entry(handle, &kdb, &adb);
432 krb5_db_free_principal(handle->context, &kdb, 1);
435 if ((mask & KADM5_POLICY)) {
436 /* decrement the policy ref count */
438 polent.policy_refcnt--;
440 * if this fails, there's nothing we can do anyway. the
441 * policy refcount wil be too high.
443 (void) kadm5_modify_policy_internal(handle->lhandle, &polent,
447 if (mask & KADM5_POLICY)
448 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
452 if (mask & KADM5_POLICY)
453 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
460 kadm5_delete_principal(void *server_handle, krb5_principal principal)
463 kadm5_policy_ent_rec polent;
465 osa_princ_ent_rec adb;
466 kadm5_server_handle_t handle = server_handle;
468 CHECK_HANDLE(server_handle);
470 krb5_clear_error_message(handle->context);
472 if (principal == NULL)
475 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
478 if ((adb.aux_attributes & KADM5_POLICY)) {
479 if ((ret = kadm5_get_policy(handle->lhandle,
480 adb.policy, &polent))
482 polent.policy_refcnt--;
483 if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent,
486 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
487 kdb_free_entry(handle, &kdb, &adb);
491 if ((ret = kadm5_free_policy_ent(handle->lhandle, &polent))) {
492 kdb_free_entry(handle, &kdb, &adb);
497 ret = kdb_delete_entry(handle, principal);
499 kdb_free_entry(handle, &kdb, &adb);
505 kadm5_modify_principal(void *server_handle,
506 kadm5_principal_ent_t entry, long mask)
509 kadm5_policy_ent_rec npol, opol;
510 int have_npol = 0, have_opol = 0;
512 krb5_tl_data *tl_data_orig;
513 osa_princ_ent_rec adb;
514 kadm5_server_handle_t handle = server_handle;
516 CHECK_HANDLE(server_handle);
518 krb5_clear_error_message(handle->context);
520 if((mask & KADM5_PRINCIPAL) || (mask & KADM5_LAST_PWD_CHANGE) ||
521 (mask & KADM5_MOD_TIME) || (mask & KADM5_MOD_NAME) ||
522 (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) ||
523 (mask & KADM5_KEY_DATA) || (mask & KADM5_LAST_SUCCESS) ||
524 (mask & KADM5_LAST_FAILED))
525 return KADM5_BAD_MASK;
526 if((mask & ~ALL_PRINC_MASK))
527 return KADM5_BAD_MASK;
528 if((mask & KADM5_POLICY) && (mask & KADM5_POLICY_CLR))
529 return KADM5_BAD_MASK;
530 if(entry == (kadm5_principal_ent_t) NULL)
532 if (mask & KADM5_TL_DATA) {
533 tl_data_orig = entry->tl_data;
534 while (tl_data_orig) {
535 if (tl_data_orig->tl_data_type < 256)
536 return KADM5_BAD_TL_TYPE;
537 tl_data_orig = tl_data_orig->tl_data_next;
541 ret = kdb_get_entry(handle, entry->principal, &kdb, &adb);
546 * This is pretty much the same as create ...
549 if ((mask & KADM5_POLICY)) {
550 /* get the new policy */
551 ret = kadm5_get_policy(handle->lhandle, entry->policy, &npol);
555 ret = KADM5_BAD_POLICY;
557 case KADM5_UNK_POLICY:
558 case KADM5_BAD_POLICY:
559 ret = KADM5_UNK_POLICY;
566 /* if we already have a policy, get it to decrement the refcnt */
567 if(adb.aux_attributes & KADM5_POLICY) {
568 /* ... but not if the old and new are the same */
569 if(strcmp(adb.policy, entry->policy)) {
570 ret = kadm5_get_policy(handle->lhandle,
574 case KADM5_BAD_POLICY:
575 case KADM5_UNK_POLICY:
579 opol.policy_refcnt--;
585 npol.policy_refcnt++;
587 } else npol.policy_refcnt++;
589 /* set us up to use the new policy */
590 adb.aux_attributes |= KADM5_POLICY;
593 adb.policy = strdup(entry->policy);
595 /* set pw_max_life based on new policy */
596 if (npol.pw_max_life) {
597 ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb,
598 &(kdb.pw_expiration));
601 kdb.pw_expiration += npol.pw_max_life;
603 kdb.pw_expiration = 0;
607 if ((mask & KADM5_POLICY_CLR) &&
608 (adb.aux_attributes & KADM5_POLICY)) {
609 ret = kadm5_get_policy(handle->lhandle, adb.policy, &opol);
612 case KADM5_BAD_POLICY:
613 case KADM5_UNK_POLICY:
622 adb.aux_attributes &= ~KADM5_POLICY;
623 kdb.pw_expiration = 0;
624 opol.policy_refcnt--;
632 if (((mask & KADM5_POLICY) || (mask & KADM5_POLICY_CLR)) &&
635 kadm5_modify_policy_internal(handle->lhandle, &opol,
636 KADM5_REF_COUNT))) ||
639 kadm5_modify_policy_internal(handle->lhandle, &npol,
643 if ((mask & KADM5_ATTRIBUTES))
644 kdb.attributes = entry->attributes;
645 if ((mask & KADM5_MAX_LIFE))
646 kdb.max_life = entry->max_life;
647 if ((mask & KADM5_PRINC_EXPIRE_TIME))
648 kdb.expiration = entry->princ_expire_time;
649 if (mask & KADM5_PW_EXPIRATION)
650 kdb.pw_expiration = entry->pw_expiration;
651 if (mask & KADM5_MAX_RLIFE)
652 kdb.max_renewable_life = entry->max_renewable_life;
653 if (mask & KADM5_FAIL_AUTH_COUNT)
654 kdb.fail_auth_count = entry->fail_auth_count;
656 if((mask & KADM5_KVNO)) {
657 for (i = 0; i < kdb.n_key_data; i++)
658 kdb.key_data[i].key_data_kvno = entry->kvno;
661 if (mask & KADM5_TL_DATA) {
664 /* may have to change the version number of the API. Updates the list with the given tl_data rather than over-writting */
666 for (tl = entry->tl_data; tl;
667 tl = tl->tl_data_next)
669 ret = krb5_dbe_update_tl_data(handle->context, &kdb, tl);
677 /* let the mask propagate to the database provider */
680 ret = kdb_put_entry(handle, &kdb, &adb);
686 ret2 = kadm5_free_policy_ent(handle->lhandle, &opol);
687 ret = ret ? ret : ret2;
690 ret2 = kadm5_free_policy_ent(handle->lhandle, &npol);
691 ret = ret ? ret : ret2;
693 kdb_free_entry(handle, &kdb, &adb);
698 kadm5_rename_principal(void *server_handle,
699 krb5_principal source, krb5_principal target)
702 osa_princ_ent_rec adb;
704 kadm5_server_handle_t handle = server_handle;
706 CHECK_HANDLE(server_handle);
708 krb5_clear_error_message(handle->context);
710 if (source == NULL || target == NULL)
713 if ((ret = kdb_get_entry(handle, target, &kdb, &adb)) == 0) {
714 kdb_free_entry(handle, &kdb, &adb);
718 if ((ret = kdb_get_entry(handle, source, &kdb, &adb)))
721 /* this is kinda gross, but unavoidable */
723 for (i=0; i<kdb.n_key_data; i++) {
724 if ((kdb.key_data[i].key_data_ver == 1) ||
725 (kdb.key_data[i].key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL)) {
726 ret = KADM5_NO_RENAME_SALT;
731 kadm5_free_principal(handle->context, kdb.princ);
732 ret = kadm5_copy_principal(handle->context, target, &kdb.princ);
734 kdb.princ = NULL; /* so freeing the dbe doesn't lose */
738 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
741 ret = kdb_delete_entry(handle, source);
744 kdb_free_entry(handle, &kdb, &adb);
749 kadm5_get_principal(void *server_handle, krb5_principal principal,
750 kadm5_principal_ent_t entry,
754 osa_princ_ent_rec adb;
755 krb5_error_code ret = 0;
758 kadm5_server_handle_t handle = server_handle;
760 CHECK_HANDLE(server_handle);
762 krb5_clear_error_message(handle->context);
765 * In version 1, all the defined fields are always returned.
766 * entry is a pointer to a kadm5_principal_ent_t_v1 that should be
767 * filled with allocated memory.
771 memset(entry, 0, sizeof(*entry));
773 if (principal == NULL)
776 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
779 if ((mask & KADM5_POLICY) &&
780 adb.policy && (adb.aux_attributes & KADM5_POLICY)) {
781 if ((entry->policy = strdup(adb.policy)) == NULL) {
787 if (mask & KADM5_AUX_ATTRIBUTES)
788 entry->aux_attributes = adb.aux_attributes;
790 if ((mask & KADM5_PRINCIPAL) &&
791 (ret = krb5_copy_principal(handle->context, kdb.princ,
792 &entry->principal))) {
796 if (mask & KADM5_PRINC_EXPIRE_TIME)
797 entry->princ_expire_time = kdb.expiration;
799 if ((mask & KADM5_LAST_PWD_CHANGE) &&
800 (ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb,
801 &(entry->last_pwd_change)))) {
805 if (mask & KADM5_PW_EXPIRATION)
806 entry->pw_expiration = kdb.pw_expiration;
807 if (mask & KADM5_MAX_LIFE)
808 entry->max_life = kdb.max_life;
810 /* this is a little non-sensical because the function returns two */
811 /* values that must be checked separately against the mask */
812 if ((mask & KADM5_MOD_NAME) || (mask & KADM5_MOD_TIME)) {
813 ret = krb5_dbe_lookup_mod_princ_data(handle->context, &kdb,
820 if (! (mask & KADM5_MOD_TIME))
822 if (! (mask & KADM5_MOD_NAME)) {
823 krb5_free_principal(handle->context, entry->principal);
824 entry->principal = NULL;
828 if (mask & KADM5_ATTRIBUTES)
829 entry->attributes = kdb.attributes;
831 if (mask & KADM5_KVNO)
832 for (entry->kvno = 0, i=0; i<kdb.n_key_data; i++)
833 if (kdb.key_data[i].key_data_kvno > entry->kvno)
834 entry->kvno = kdb.key_data[i].key_data_kvno;
836 ret = krb5_dbe_lookup_mkvno(handle->context, &kdb, &entry->mkvno);
840 if (mask & KADM5_MAX_RLIFE)
841 entry->max_renewable_life = kdb.max_renewable_life;
842 if (mask & KADM5_LAST_SUCCESS)
843 entry->last_success = kdb.last_success;
844 if (mask & KADM5_LAST_FAILED)
845 entry->last_failed = kdb.last_failed;
846 if (mask & KADM5_FAIL_AUTH_COUNT)
847 entry->fail_auth_count = kdb.fail_auth_count;
848 if (mask & KADM5_TL_DATA) {
849 krb5_tl_data *tl, *tl2;
851 entry->tl_data = NULL;
855 if (tl->tl_data_type > 255) {
856 if ((tl2 = dup_tl_data(tl)) == NULL) {
860 tl2->tl_data_next = entry->tl_data;
861 entry->tl_data = tl2;
865 tl = tl->tl_data_next;
868 if (mask & KADM5_KEY_DATA) {
869 entry->n_key_data = kdb.n_key_data;
870 if(entry->n_key_data) {
871 entry->key_data = malloc(entry->n_key_data*sizeof(krb5_key_data));
872 if (entry->key_data == NULL) {
877 entry->key_data = NULL;
879 for (i = 0; i < entry->n_key_data; i++)
880 ret = krb5_copy_key_data_contents(handle->context,
882 &entry->key_data[i]);
890 if (ret && entry->principal)
891 krb5_free_principal(handle->context, entry->principal);
892 kdb_free_entry(handle, &kdb, &adb);
898 * Function: check_pw_reuse
900 * Purpose: Check if a key appears in a list of keys, in order to
901 * enforce password history.
905 * context (r) the krb5 context
906 * hist_keyblock (r) the key that hist_key_data is
908 * n_new_key_data (r) length of new_key_data
909 * new_key_data (r) keys to check against
910 * pw_hist_data, encrypted in hist_keyblock
911 * n_pw_hist_data (r) length of pw_hist_data
912 * pw_hist_data (r) passwords to check new_key_data against
915 * For each new_key in new_key_data:
916 * decrypt new_key with the master_keyblock
917 * for each password in pw_hist_data:
918 * for each hist_key in password:
919 * decrypt hist_key with hist_keyblock
920 * compare the new_key and hist_key
922 * Returns krb5 errors, KADM5_PASS_RESUSE if a key in
923 * new_key_data is the same as a key in pw_hist_data, or 0.
926 check_pw_reuse(krb5_context context,
928 krb5_keyblock *hist_keyblock,
929 int n_new_key_data, krb5_key_data *new_key_data,
930 unsigned int n_pw_hist_data, osa_pw_hist_ent *pw_hist_data)
933 krb5_keyblock newkey, histkey;
936 for (x = 0; x < n_new_key_data; x++) {
937 ret = krb5_dbekd_decrypt_key_data(context,
943 for (y = 0; y < n_pw_hist_data; y++) {
944 for (z = 0; z < pw_hist_data[y].n_key_data; z++) {
945 ret = krb5_dbekd_decrypt_key_data(context,
947 &pw_hist_data[y].key_data[z],
952 if ((newkey.length == histkey.length) &&
953 (newkey.enctype == histkey.enctype) &&
954 (memcmp(newkey.contents, histkey.contents,
955 histkey.length) == 0)) {
956 krb5_free_keyblock_contents(context, &histkey);
957 krb5_free_keyblock_contents(context, &newkey);
959 return(KADM5_PASS_REUSE);
961 krb5_free_keyblock_contents(context, &histkey);
964 krb5_free_keyblock_contents(context, &newkey);
971 * Function: create_history_entry
973 * Purpose: Creates a password history entry from an array of
978 * context (r) krb5_context to use
979 * n_key_data (r) number of elements in key_data
980 * key_data (r) keys to add to the history entry
981 * hist (w) history entry to fill in
985 * hist->key_data is allocated to store n_key_data key_datas. Each
986 * element of key_data is decrypted with master_keyblock, re-encrypted
987 * in hist_key, and added to hist->key_data. hist->n_key_data is
991 int create_history_entry(krb5_context context, krb5_keyblock *mkey, int n_key_data,
992 krb5_key_data *key_data, osa_pw_hist_ent *hist)
998 hist->key_data = (krb5_key_data*)malloc(n_key_data*sizeof(krb5_key_data));
999 if (hist->key_data == NULL)
1001 memset(hist->key_data, 0, n_key_data*sizeof(krb5_key_data));
1003 for (i = 0; i < n_key_data; i++) {
1004 ret = krb5_dbekd_decrypt_key_data(context,
1011 ret = krb5_dbekd_encrypt_key_data(context, &hist_key,
1013 key_data[i].key_data_kvno,
1014 &hist->key_data[i]);
1018 krb5_free_keyblock_contents(context, &key);
1019 /* krb5_free_keysalt(context, &salt); */
1022 hist->n_key_data = n_key_data;
1027 void free_history_entry(krb5_context context, osa_pw_hist_ent *hist)
1031 for (i = 0; i < hist->n_key_data; i++)
1032 krb5_free_key_data_contents(context, &hist->key_data[i]);
1033 free(hist->key_data);
1037 * Function: add_to_history
1039 * Purpose: Adds a password to a principal's password history.
1043 * context (r) krb5_context to use
1044 * adb (r/w) admin principal entry to add keys to
1045 * pol (r) adb's policy
1046 * pw (r) keys for the password to add to adb's key history
1050 * add_to_history adds a single password to adb's password history.
1051 * pw contains n_key_data keys in its key_data, in storage should be
1052 * allocated but not freed by the caller (XXX blech!).
1054 * This function maintains adb->old_keys as a circular queue. It
1055 * starts empty, and grows each time this function is called until it
1056 * is pol->pw_history_num items long. adb->old_key_len holds the
1057 * number of allocated entries in the array, and must therefore be [0,
1058 * pol->pw_history_num). adb->old_key_next is the index into the
1059 * array where the next element should be written, and must be [0,
1060 * adb->old_key_len).
1062 static kadm5_ret_t add_to_history(krb5_context context,
1063 osa_princ_ent_t adb,
1064 kadm5_policy_ent_t pol,
1065 osa_pw_hist_ent *pw)
1067 osa_pw_hist_ent *histp;
1069 unsigned int i, knext, nkeys;
1071 nhist = pol->pw_history_num;
1072 /* A history of 1 means just check the current password */
1076 nkeys = adb->old_key_len;
1077 knext = adb->old_key_next;
1078 /* resize the adb->old_keys array if necessary */
1079 if (nkeys + 1 < nhist) {
1080 if (adb->old_keys == NULL) {
1081 adb->old_keys = (osa_pw_hist_ent *)
1082 malloc((nkeys + 1) * sizeof (osa_pw_hist_ent));
1084 adb->old_keys = (osa_pw_hist_ent *)
1085 realloc(adb->old_keys,
1086 (nkeys + 1) * sizeof (osa_pw_hist_ent));
1088 if (adb->old_keys == NULL)
1091 memset(&adb->old_keys[nkeys], 0, sizeof(osa_pw_hist_ent));
1092 nkeys = ++adb->old_key_len;
1094 * To avoid losing old keys, shift forward each entry after
1097 for (i = nkeys - 1; i > knext; i--) {
1098 adb->old_keys[i] = adb->old_keys[i - 1];
1100 memset(&adb->old_keys[knext], 0, sizeof(osa_pw_hist_ent));
1101 } else if (nkeys + 1 > nhist) {
1103 * The policy must have changed! Shrink the array.
1104 * Can't simply realloc() down, since it might be wrapped.
1105 * To understand the arithmetic below, note that we are
1106 * copying into new positions 0 .. N-1 from old positions
1107 * old_key_next-N .. old_key_next-1, modulo old_key_len,
1108 * where N = pw_history_num - 1 is the length of the
1109 * shortened list. Matt Crawford, FNAL
1112 * M = adb->old_key_len, N = pol->pw_history_num - 1
1114 * tmp[0] .. tmp[N-1] = old[(knext-N)%M] .. old[(knext-1)%M]
1119 tmp = (osa_pw_hist_ent *)
1120 malloc((nhist - 1) * sizeof (osa_pw_hist_ent));
1123 for (i = 0; i < nhist - 1; i++) {
1125 * Add nkeys once before taking remainder to avoid
1128 j = (i + nkeys + knext - (nhist - 1)) % nkeys;
1129 tmp[i] = adb->old_keys[j];
1131 /* Now free the ones we don't keep (the oldest ones) */
1132 for (i = 0; i < nkeys - (nhist - 1); i++) {
1133 j = (i + nkeys + knext) % nkeys;
1134 histp = &adb->old_keys[j];
1135 for (j = 0; j < histp->n_key_data; j++) {
1136 krb5_free_key_data_contents(context, &histp->key_data[j]);
1138 free(histp->key_data);
1140 free(adb->old_keys);
1141 adb->old_keys = tmp;
1142 nkeys = adb->old_key_len = nhist - 1;
1143 knext = adb->old_key_next = 0;
1147 * If nhist decreased since the last password change, and nkeys+1
1148 * is less than the previous nhist, it is possible for knext to
1149 * index into unallocated space. This condition would not be
1150 * caught by the resizing code above.
1152 if (knext + 1 > nkeys)
1153 knext = adb->old_key_next = 0;
1154 /* free the old pw history entry if it contains data */
1155 histp = &adb->old_keys[knext];
1156 for (i = 0; i < histp->n_key_data; i++)
1157 krb5_free_key_data_contents(context, &histp->key_data[i]);
1158 free(histp->key_data);
1160 /* store the new entry */
1161 adb->old_keys[knext] = *pw;
1163 /* update the next pointer */
1164 if (++adb->old_key_next == nhist - 1)
1165 adb->old_key_next = 0;
1170 /* FIXME: don't use global variable for this */
1171 krb5_boolean use_password_server = 0;
1173 #ifdef USE_PASSWORD_SERVER
1175 kadm5_use_password_server (void)
1177 return use_password_server;
1182 kadm5_set_use_password_server (void)
1184 use_password_server = 1;
1187 #ifdef USE_PASSWORD_SERVER
1190 * kadm5_launch_task () runs a program (task_path) to synchronize the
1191 * Apple password server with the Kerberos database. Password server
1192 * programs can receive arguments on the command line (task_argv)
1193 * and a block of data via stdin (data_buffer).
1195 * Because a failure to communicate with the tool results in the
1196 * password server falling out of sync with the database,
1197 * kadm5_launch_task() always fails if it can't talk to the tool.
1201 kadm5_launch_task (krb5_context context,
1202 const char *task_path, char * const task_argv[],
1208 ret = pipe (data_pipe);
1213 pid_t pid = fork ();
1216 close (data_pipe[0]);
1217 close (data_pipe[1]);
1218 } else if (pid == 0) {
1221 if (dup2 (data_pipe[0], STDIN_FILENO) == -1)
1224 close (data_pipe[0]);
1225 close (data_pipe[1]);
1227 execv (task_path, task_argv);
1229 _exit (1); /* Fail if execv fails */
1236 close (data_pipe[0]);
1238 /* Write out the buffer to the child, add \n */
1240 if (krb5_net_write (context, data_pipe[1], buffer, strlen (buffer)) < 0
1241 || krb5_net_write (context, data_pipe[1], "\n", 1) < 0)
1243 /* kill the child to make sure waitpid() won't hang later */
1245 kill (pid, SIGKILL);
1248 close (data_pipe[1]);
1250 waitpid (pid, &status, 0);
1253 if (WIFEXITED (status)) {
1254 /* child read password and exited. Check the return value. */
1255 if ((WEXITSTATUS (status) != 0) && (WEXITSTATUS (status) != 252)) {
1256 ret = KRB5KDC_ERR_POLICY; /* password change rejected */
1259 /* child read password but crashed or was killed */
1260 ret = KRB5KRB_ERR_GENERIC; /* FIXME: better error */
1272 kadm5_chpass_principal(void *server_handle,
1273 krb5_principal principal, char *password)
1276 kadm5_chpass_principal_3(server_handle, principal, FALSE,
1281 kadm5_chpass_principal_3(void *server_handle,
1282 krb5_principal principal, krb5_boolean keepold,
1283 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1287 kadm5_policy_ent_rec pol;
1288 osa_princ_ent_rec adb;
1289 krb5_db_entry kdb, kdb_save;
1290 int ret, ret2, last_pwd, hist_added;
1292 kadm5_server_handle_t handle = server_handle;
1293 osa_pw_hist_ent hist;
1294 krb5_keyblock *act_mkey;
1297 CHECK_HANDLE(server_handle);
1299 krb5_clear_error_message(handle->context);
1302 memset(&hist, 0, sizeof(hist));
1304 if (principal == NULL || password == NULL)
1306 if ((krb5_principal_compare(handle->context,
1307 principal, hist_princ)) == TRUE)
1308 return KADM5_PROTECT_PRINCIPAL;
1310 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1313 /* we are going to need the current keys after the new keys are set */
1314 if ((ret = kdb_get_entry(handle, principal, &kdb_save, NULL))) {
1315 kdb_free_entry(handle, &kdb, &adb);
1319 if ((adb.aux_attributes & KADM5_POLICY)) {
1320 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &pol)))
1325 if ((ret = passwd_check(handle, password, adb.aux_attributes &
1326 KADM5_POLICY, &pol, principal)))
1329 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
1330 active_mkey_list, &act_kvno, &act_mkey);
1334 ret = krb5_dbe_cpw(handle->context, act_mkey,
1335 n_ks_tuple?ks_tuple:handle->params.keysalts,
1336 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
1337 password, 0 /* increment kvno */,
1342 ret = krb5_dbe_update_mkvno(handle->context, &kdb, act_kvno);
1346 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1348 ret = krb5_timeofday(handle->context, &now);
1352 if ((adb.aux_attributes & KADM5_POLICY)) {
1353 /* the policy was loaded before */
1355 ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1362 * The spec says this check is overridden if the caller has
1363 * modify privilege. The admin server therefore makes this
1364 * check itself (in chpass_principal_wrapper, misc.c). A
1365 * local caller implicitly has all authorization bits.
1367 if ((now - last_pwd) < pol.pw_min_life &&
1368 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1369 ret = KADM5_PASS_TOOSOON;
1374 ret = create_history_entry(handle->context,
1376 kdb_save.n_key_data,
1377 kdb_save.key_data, &hist);
1381 ret = check_pw_reuse(handle->context, act_mkey, &hist_key,
1382 kdb.n_key_data, kdb.key_data,
1387 if (pol.pw_history_num > 1) {
1388 if (adb.admin_history_kvno != hist_kvno) {
1389 ret = KADM5_BAD_HIST_KEY;
1393 ret = check_pw_reuse(handle->context, act_mkey, &hist_key,
1394 kdb.n_key_data, kdb.key_data,
1395 adb.old_key_len, adb.old_keys);
1399 ret = add_to_history(handle->context, &adb, &pol, &hist);
1405 if (pol.pw_max_life)
1406 kdb.pw_expiration = now + pol.pw_max_life;
1408 kdb.pw_expiration = 0;
1410 kdb.pw_expiration = 0;
1413 #ifdef USE_PASSWORD_SERVER
1414 if (kadm5_use_password_server () &&
1415 (krb5_princ_size (handle->context, principal) == 1)) {
1416 krb5_data *princ = krb5_princ_component (handle->context, principal, 0);
1417 const char *path = "/usr/sbin/mkpassdb";
1418 char *argv[] = { "mkpassdb", "-setpassword", NULL, NULL };
1419 char *pstring = NULL;
1422 pstring = malloc ((princ->length + 1) * sizeof (char));
1423 if (pstring == NULL) { ret = ENOMEM; }
1427 memcpy (pstring, princ->data, princ->length);
1428 pstring [princ->length] = '\0';
1431 ret = kadm5_launch_task (handle->context, path, argv, password);
1434 if (pstring != NULL)
1442 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
1446 /* key data and attributes changed, let the database provider know */
1447 kdb.mask = KADM5_KEY_DATA | KADM5_ATTRIBUTES /* | KADM5_CPW_FUNCTION */;
1449 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1454 if (!hist_added && hist.key_data)
1455 free_history_entry(handle->context, &hist);
1456 kdb_free_entry(handle, &kdb, &adb);
1457 kdb_free_entry(handle, &kdb_save, NULL);
1458 krb5_db_free_principal(handle->context, &kdb, 1);
1460 if (have_pol && (ret2 = kadm5_free_policy_ent(handle->lhandle, &pol))
1468 kadm5_randkey_principal(void *server_handle,
1469 krb5_principal principal,
1470 krb5_keyblock **keyblocks,
1474 kadm5_randkey_principal_3(server_handle, principal,
1479 kadm5_randkey_principal_3(void *server_handle,
1480 krb5_principal principal,
1481 krb5_boolean keepold,
1482 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1483 krb5_keyblock **keyblocks,
1487 osa_princ_ent_rec adb;
1489 kadm5_policy_ent_rec pol;
1490 int ret, last_pwd, have_pol = 0;
1491 kadm5_server_handle_t handle = server_handle;
1492 krb5_keyblock *act_mkey;
1497 CHECK_HANDLE(server_handle);
1499 krb5_clear_error_message(handle->context);
1501 if (principal == NULL)
1503 if (hist_princ && /* this will be NULL when initializing the databse */
1504 ((krb5_principal_compare(handle->context,
1505 principal, hist_princ)) == TRUE))
1506 return KADM5_PROTECT_PRINCIPAL;
1508 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1511 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
1512 active_mkey_list, NULL, &act_mkey);
1516 ret = krb5_dbe_crk(handle->context, act_mkey,
1517 n_ks_tuple?ks_tuple:handle->params.keysalts,
1518 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
1524 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1526 ret = krb5_timeofday(handle->context, &now);
1530 if ((adb.aux_attributes & KADM5_POLICY)) {
1531 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1536 ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1543 * The spec says this check is overridden if the caller has
1544 * modify privilege. The admin server therefore makes this
1545 * check itself (in chpass_principal_wrapper, misc.c). A
1546 * local caller implicitly has all authorization bits.
1548 if((now - last_pwd) < pol.pw_min_life &&
1549 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1550 ret = KADM5_PASS_TOOSOON;
1555 if(pol.pw_history_num > 1) {
1556 if(adb.admin_history_kvno != hist_kvno) {
1557 ret = KADM5_BAD_HIST_KEY;
1561 ret = check_pw_reuse(handle->context, act_mkey, &hist_key,
1562 kdb.n_key_data, kdb.key_data,
1563 adb.old_key_len, adb.old_keys);
1567 if (pol.pw_max_life)
1568 kdb.pw_expiration = now + pol.pw_max_life;
1570 kdb.pw_expiration = 0;
1572 kdb.pw_expiration = 0;
1575 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
1580 ret = decrypt_key_data(handle->context, act_mkey,
1581 kdb.n_key_data, kdb.key_data,
1587 /* key data changed, let the database provider know */
1588 kdb.mask = KADM5_KEY_DATA /* | KADM5_RANDKEY_USED */;
1590 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1595 kdb_free_entry(handle, &kdb, &adb);
1597 kadm5_free_policy_ent(handle->lhandle, &pol);
1603 * kadm5_setv4key_principal:
1605 * Set only ONE key of the principal, removing all others. This key
1606 * must have the DES_CBC_CRC enctype and is entered as having the
1607 * krb4 salttype. This is to enable things like kadmind4 to work.
1610 kadm5_setv4key_principal(void *server_handle,
1611 krb5_principal principal,
1612 krb5_keyblock *keyblock)
1615 osa_princ_ent_rec adb;
1617 kadm5_policy_ent_rec pol;
1618 krb5_keysalt keysalt;
1619 int i, k, kvno, ret, have_pol = 0;
1623 kadm5_server_handle_t handle = server_handle;
1624 krb5_key_data tmp_key_data;
1625 krb5_keyblock *act_mkey;
1627 memset( &tmp_key_data, 0, sizeof(tmp_key_data));
1629 CHECK_HANDLE(server_handle);
1631 krb5_clear_error_message(handle->context);
1633 if (principal == NULL || keyblock == NULL)
1635 if (hist_princ && /* this will be NULL when initializing the databse */
1636 ((krb5_principal_compare(handle->context,
1637 principal, hist_princ)) == TRUE))
1638 return KADM5_PROTECT_PRINCIPAL;
1640 if (keyblock->enctype != ENCTYPE_DES_CBC_CRC)
1641 return KADM5_SETV4KEY_INVAL_ENCTYPE;
1643 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1646 for (kvno = 0, i=0; i<kdb.n_key_data; i++)
1647 if (kdb.key_data[i].key_data_kvno > kvno)
1648 kvno = kdb.key_data[i].key_data_kvno;
1650 if (kdb.key_data != NULL)
1651 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
1653 kdb.key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, sizeof(krb5_key_data));
1654 if (kdb.key_data == NULL)
1656 memset(kdb.key_data, 0, sizeof(krb5_key_data));
1658 keysalt.type = KRB5_KDB_SALTTYPE_V4;
1659 /* XXX data.magic? */
1660 keysalt.data.length = 0;
1661 keysalt.data.data = NULL;
1663 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
1664 active_mkey_list, NULL, &act_mkey);
1668 /* use tmp_key_data as temporary location and reallocate later */
1669 ret = krb5_dbekd_encrypt_key_data(handle->context, act_mkey,
1670 keyblock, &keysalt, kvno + 1,
1676 for (k = 0; k < tmp_key_data.key_data_ver; k++) {
1677 kdb.key_data->key_data_type[k] = tmp_key_data.key_data_type[k];
1678 kdb.key_data->key_data_length[k] = tmp_key_data.key_data_length[k];
1679 if (tmp_key_data.key_data_contents[k]) {
1680 kdb.key_data->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]);
1681 if (kdb.key_data->key_data_contents[k] == NULL) {
1682 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
1683 kdb.key_data = NULL;
1688 memcpy (kdb.key_data->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
1690 memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
1691 free (tmp_key_data.key_data_contents[k]);
1692 tmp_key_data.key_data_contents[k] = NULL;
1698 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1700 ret = krb5_timeofday(handle->context, &now);
1704 if ((adb.aux_attributes & KADM5_POLICY)) {
1705 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1712 * The spec says this check is overridden if the caller has
1713 * modify privilege. The admin server therefore makes this
1714 * check itself (in chpass_principal_wrapper, misc.c). A
1715 * local caller implicitly has all authorization bits.
1717 if (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1720 if((now - last_pwd) < pol.pw_min_life &&
1721 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1722 ret = KADM5_PASS_TOOSOON;
1728 * Should we be checking/updating pw history here?
1730 if(pol.pw_history_num > 1) {
1731 if(adb.admin_history_kvno != hist_kvno) {
1732 ret = KADM5_BAD_HIST_KEY;
1736 if (ret = check_pw_reuse(handle->context,
1738 kdb.n_key_data, kdb.key_data,
1739 adb.old_key_len, adb.old_keys))
1744 if (pol.pw_max_life)
1745 kdb.pw_expiration = now + pol.pw_max_life;
1747 kdb.pw_expiration = 0;
1749 kdb.pw_expiration = 0;
1752 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
1756 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1761 for (i = 0; i < tmp_key_data.key_data_ver; i++) {
1762 if (tmp_key_data.key_data_contents[i]) {
1763 memset (tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]);
1764 free (tmp_key_data.key_data_contents[i]);
1768 kdb_free_entry(handle, &kdb, &adb);
1770 kadm5_free_policy_ent(handle->lhandle, &pol);
1776 kadm5_setkey_principal(void *server_handle,
1777 krb5_principal principal,
1778 krb5_keyblock *keyblocks,
1782 kadm5_setkey_principal_3(server_handle, principal,
1788 kadm5_setkey_principal_3(void *server_handle,
1789 krb5_principal principal,
1790 krb5_boolean keepold,
1791 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1792 krb5_keyblock *keyblocks,
1796 osa_princ_ent_rec adb;
1798 kadm5_policy_ent_rec pol;
1799 krb5_key_data *old_key_data;
1801 int i, j, k, kvno, ret, have_pol = 0;
1805 kadm5_server_handle_t handle = server_handle;
1806 krb5_boolean similar;
1807 krb5_keysalt keysalt;
1808 krb5_key_data tmp_key_data;
1809 krb5_key_data *tptr;
1810 krb5_keyblock *act_mkey;
1812 CHECK_HANDLE(server_handle);
1814 krb5_clear_error_message(handle->context);
1816 if (principal == NULL || keyblocks == NULL)
1818 if (hist_princ && /* this will be NULL when initializing the databse */
1819 ((krb5_principal_compare(handle->context,
1820 principal, hist_princ)) == TRUE))
1821 return KADM5_PROTECT_PRINCIPAL;
1823 for (i = 0; i < n_keys; i++) {
1824 for (j = i+1; j < n_keys; j++) {
1825 if ((ret = krb5_c_enctype_compare(handle->context,
1826 keyblocks[i].enctype,
1827 keyblocks[j].enctype,
1832 if (ks_tuple[i].ks_salttype == ks_tuple[j].ks_salttype)
1833 return KADM5_SETKEY_DUP_ENCTYPES;
1835 return KADM5_SETKEY_DUP_ENCTYPES;
1840 if (n_ks_tuple && n_ks_tuple != n_keys)
1841 return KADM5_SETKEY3_ETYPE_MISMATCH;
1843 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1846 for (kvno = 0, i=0; i<kdb.n_key_data; i++)
1847 if (kdb.key_data[i].key_data_kvno > kvno)
1848 kvno = kdb.key_data[i].key_data_kvno;
1851 old_key_data = kdb.key_data;
1852 n_old_keys = kdb.n_key_data;
1854 if (kdb.key_data != NULL)
1855 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
1857 old_key_data = NULL;
1860 kdb.key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, (n_keys+n_old_keys)
1861 *sizeof(krb5_key_data));
1862 if (kdb.key_data == NULL) {
1867 memset(kdb.key_data, 0, (n_keys+n_old_keys)*sizeof(krb5_key_data));
1870 for (i = 0; i < n_keys; i++) {
1872 keysalt.type = ks_tuple[i].ks_salttype;
1873 keysalt.data.length = 0;
1874 keysalt.data.data = NULL;
1875 if (ks_tuple[i].ks_enctype != keyblocks[i].enctype) {
1876 ret = KADM5_SETKEY3_ETYPE_MISMATCH;
1880 memset (&tmp_key_data, 0, sizeof(tmp_key_data));
1882 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
1883 active_mkey_list, NULL, &act_mkey);
1887 ret = krb5_dbekd_encrypt_key_data(handle->context,
1890 n_ks_tuple ? &keysalt : NULL,
1896 tptr = &kdb.key_data[i];
1897 tptr->key_data_ver = tmp_key_data.key_data_ver;
1898 tptr->key_data_kvno = tmp_key_data.key_data_kvno;
1899 for (k = 0; k < tmp_key_data.key_data_ver; k++) {
1900 tptr->key_data_type[k] = tmp_key_data.key_data_type[k];
1901 tptr->key_data_length[k] = tmp_key_data.key_data_length[k];
1902 if (tmp_key_data.key_data_contents[k]) {
1903 tptr->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]);
1904 if (tptr->key_data_contents[k] == NULL) {
1906 for (i1 = k; i1 < tmp_key_data.key_data_ver; i1++) {
1907 if (tmp_key_data.key_data_contents[i1]) {
1908 memset (tmp_key_data.key_data_contents[i1], 0, tmp_key_data.key_data_length[i1]);
1909 free (tmp_key_data.key_data_contents[i1]);
1916 memcpy (tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
1918 memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
1919 free (tmp_key_data.key_data_contents[k]);
1920 tmp_key_data.key_data_contents[k] = NULL;
1926 /* copy old key data if necessary */
1927 for (i = 0; i < n_old_keys; i++) {
1928 kdb.key_data[i+n_keys] = old_key_data[i];
1929 memset(&old_key_data[i], 0, sizeof (krb5_key_data));
1934 krb5_db_free(handle->context, old_key_data);
1936 /* assert(kdb.n_key_data == n_keys + n_old_keys) */
1937 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1939 if ((ret = krb5_timeofday(handle->context, &now)))
1942 if ((adb.aux_attributes & KADM5_POLICY)) {
1943 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1950 * The spec says this check is overridden if the caller has
1951 * modify privilege. The admin server therefore makes this
1952 * check itself (in chpass_principal_wrapper, misc.c). A
1953 * local caller implicitly has all authorization bits.
1955 if (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1958 if((now - last_pwd) < pol.pw_min_life &&
1959 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1960 ret = KADM5_PASS_TOOSOON;
1966 * Should we be checking/updating pw history here?
1968 if (pol.pw_history_num > 1) {
1969 if(adb.admin_history_kvno != hist_kvno) {
1970 ret = KADM5_BAD_HIST_KEY;
1974 if (ret = check_pw_reuse(handle->context,
1976 kdb.n_key_data, kdb.key_data,
1977 adb.old_key_len, adb.old_keys))
1982 if (pol.pw_max_life)
1983 kdb.pw_expiration = now + pol.pw_max_life;
1985 kdb.pw_expiration = 0;
1987 kdb.pw_expiration = 0;
1990 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now)))
1993 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1998 kdb_free_entry(handle, &kdb, &adb);
2000 kadm5_free_policy_ent(handle->lhandle, &pol);
2006 * Return the list of keys like kadm5_randkey_principal,
2007 * but don't modify the principal.
2010 kadm5_get_principal_keys(void *server_handle /* IN */,
2011 krb5_principal principal /* IN */,
2012 krb5_keyblock **keyblocks /* OUT */,
2013 int *n_keys /* OUT */)
2016 osa_princ_ent_rec adb;
2018 kadm5_server_handle_t handle = server_handle;
2019 krb5_keyblock *mkey_ptr;
2024 CHECK_HANDLE(server_handle);
2026 if (principal == NULL)
2029 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
2033 if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist, &kdb,
2035 krb5_keylist_node *tmp_mkey_list;
2036 /* try refreshing master key list */
2037 /* XXX it would nice if we had the mkvno here for optimization */
2038 if (krb5_db_fetch_mkey_list(handle->context, master_princ,
2039 &master_keyblock, 0,
2040 &tmp_mkey_list) == 0) {
2041 krb5_dbe_free_key_list(handle->context, master_keylist);
2042 master_keylist = tmp_mkey_list;
2043 if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist,
2044 &kdb, &mkey_ptr))) {
2052 ret = decrypt_key_data(handle->context, mkey_ptr,
2053 kdb.n_key_data, kdb.key_data,
2061 kdb_free_entry(handle, &kdb, &adb);
2068 * Allocate an array of n_key_data krb5_keyblocks, fill in each
2069 * element with the results of decrypting the nth key in key_data with
2070 * mkey, and if n_keys is not NULL fill it in with the
2071 * number of keys decrypted.
2073 static int decrypt_key_data(krb5_context context, krb5_keyblock *mkey,
2074 int n_key_data, krb5_key_data *key_data,
2075 krb5_keyblock **keyblocks, int *n_keys)
2077 krb5_keyblock *keys;
2080 keys = (krb5_keyblock *) malloc(n_key_data*sizeof(krb5_keyblock));
2083 memset(keys, 0, n_key_data*sizeof(krb5_keyblock));
2085 for (i = 0; i < n_key_data; i++) {
2086 ret = krb5_dbekd_decrypt_key_data(context, mkey,
2090 for (; i >= 0; i--) {
2091 if (keys[i].contents) {
2092 memset (keys[i].contents, 0, keys[i].length);
2093 free( keys[i].contents );
2097 memset(keys, 0, n_key_data*sizeof(krb5_keyblock));
2105 *n_keys = n_key_data;
2111 * Function: kadm5_decrypt_key
2113 * Purpose: Retrieves and decrypts a principal key.
2117 * server_handle (r) kadm5 handle
2118 * entry (r) principal retrieved with kadm5_get_principal
2119 * ktype (r) enctype to search for, or -1 to ignore
2120 * stype (r) salt type to search for, or -1 to ignore
2121 * kvno (r) kvno to search for, -1 for max, 0 for max
2122 * only if it also matches ktype and stype
2123 * keyblock (w) keyblock to fill in
2124 * keysalt (w) keysalt to fill in, or NULL
2125 * kvnop (w) kvno to fill in, or NULL
2127 * Effects: Searches the key_data array of entry, which must have been
2128 * retrived with kadm5_get_principal with the KADM5_KEY_DATA mask, to
2129 * find a key with a specified enctype, salt type, and kvno in a
2130 * principal entry. If not found, return ENOENT. Otherwise, decrypt
2131 * it with the master key, and return the key in keyblock, the salt
2132 * in salttype, and the key version number in kvno.
2134 * If ktype or stype is -1, it is ignored for the search. If kvno is
2135 * -1, ktype and stype are ignored and the key with the max kvno is
2136 * returned. If kvno is 0, only the key with the max kvno is returned
2137 * and only if it matches the ktype and stype; otherwise, ENOENT is
2140 kadm5_ret_t kadm5_decrypt_key(void *server_handle,
2141 kadm5_principal_ent_t entry, krb5_int32
2142 ktype, krb5_int32 stype, krb5_int32
2143 kvno, krb5_keyblock *keyblock,
2144 krb5_keysalt *keysalt, int *kvnop)
2146 kadm5_server_handle_t handle = server_handle;
2147 krb5_db_entry dbent;
2148 krb5_key_data *key_data;
2149 krb5_keyblock *mkey_ptr;
2152 CHECK_HANDLE(server_handle);
2154 if (entry->n_key_data == 0 || entry->key_data == NULL)
2157 /* find_enctype only uses these two fields */
2158 dbent.n_key_data = entry->n_key_data;
2159 dbent.key_data = entry->key_data;
2160 if ((ret = krb5_dbe_find_enctype(handle->context, &dbent, ktype,
2161 stype, kvno, &key_data)))
2164 /* find_mkey only uses this field */
2165 dbent.tl_data = entry->tl_data;
2166 if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist, &dbent,
2168 krb5_keylist_node *tmp_mkey_list;
2169 /* try refreshing master key list */
2170 /* XXX it would nice if we had the mkvno here for optimization */
2171 if (krb5_db_fetch_mkey_list(handle->context, master_princ,
2172 &master_keyblock, 0, &tmp_mkey_list) == 0) {
2173 krb5_dbe_free_key_list(handle->context, master_keylist);
2174 master_keylist = tmp_mkey_list;
2175 if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist,
2176 &dbent, &mkey_ptr))) {
2184 if ((ret = krb5_dbekd_decrypt_key_data(handle->context,
2186 keyblock, keysalt)))
2190 * Coerce the enctype of the output keyblock in case we got an
2191 * inexact match on the enctype; this behavior will go away when
2192 * the key storage architecture gets redesigned for 1.3.
2195 keyblock->enctype = ktype;
2198 *kvnop = key_data->key_data_kvno;