1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
8 #if !defined(lint) && !defined(__CODECENTER__)
9 static char *rcsid = "$Header$";
12 #include <sys/types.h>
15 #include <kadm5/admin.h>
19 #include "server_internal.h"
22 #ifdef USE_PASSWORD_SERVER
29 #include <valgrind/memcheck.h>
31 #define VALGRIND_CHECK_DEFINED(LVALUE) ((void)0)
34 extern krb5_principal master_princ;
35 extern krb5_principal hist_princ;
36 extern krb5_keyblock master_keyblock;
37 extern krb5_keylist_node *master_keylist;
38 extern krb5_actkvno_node *active_mkey_list;
39 extern krb5_keyblock hist_key;
40 extern krb5_db_entry master_db;
41 extern krb5_db_entry hist_db;
42 extern krb5_kvno hist_kvno;
44 static int decrypt_key_data(krb5_context context, krb5_keyblock *mkey,
45 int n_key_data, krb5_key_data *key_data,
46 krb5_keyblock **keyblocks, int *n_keys);
48 static krb5_error_code
49 kadm5_copy_principal(krb5_context context, krb5_const_principal inprinc, krb5_principal *outprinc)
51 register krb5_principal tempprinc;
52 register int i, nelems;
54 tempprinc = (krb5_principal)krb5_db_alloc(context, NULL, sizeof(krb5_principal_data));
59 VALGRIND_CHECK_DEFINED(*inprinc);
60 *tempprinc = *inprinc;
62 nelems = (int) krb5_princ_size(context, inprinc);
63 tempprinc->data = krb5_db_alloc(context, NULL, nelems * sizeof(krb5_data));
64 if (tempprinc->data == 0) {
65 krb5_db_free(context, (char *)tempprinc);
69 for (i = 0; i < nelems; i++) {
70 unsigned int len = krb5_princ_component(context, inprinc, i)->length;
71 krb5_princ_component(context, tempprinc, i)->length = len;
72 if (((krb5_princ_component(context, tempprinc, i)->data =
73 krb5_db_alloc(context, NULL, len)) == 0) && len) {
75 krb5_db_free(context, krb5_princ_component(context, tempprinc, i)->data);
76 krb5_db_free (context, tempprinc->data);
77 krb5_db_free (context, tempprinc);
81 memcpy(krb5_princ_component(context, tempprinc, i)->data,
82 krb5_princ_component(context, inprinc, i)->data, len);
83 krb5_princ_component(context, tempprinc, i)->magic = KV5M_DATA;
86 tempprinc->realm.data =
87 krb5_db_alloc(context, NULL, tempprinc->realm.length = inprinc->realm.length);
88 if (!tempprinc->realm.data && tempprinc->realm.length) {
89 for (i = 0; i < nelems; i++)
90 krb5_db_free(context, krb5_princ_component(context, tempprinc, i)->data);
91 krb5_db_free(context, tempprinc->data);
92 krb5_db_free(context, tempprinc);
95 if (tempprinc->realm.length)
96 memcpy(tempprinc->realm.data, inprinc->realm.data,
97 inprinc->realm.length);
99 *outprinc = tempprinc;
104 kadm5_free_principal(krb5_context context, krb5_principal val)
106 register krb5_int32 i;
112 i = krb5_princ_size(context, val);
114 krb5_db_free(context, krb5_princ_component(context, val, i)->data);
115 krb5_db_free(context, val->data);
118 krb5_db_free(context, val->realm.data);
119 krb5_db_free(context, val);
123 * XXX Functions that ought to be in libkrb5.a, but aren't.
125 kadm5_ret_t krb5_copy_key_data_contents(context, from, to)
126 krb5_context context;
127 krb5_key_data *from, *to;
133 idx = (from->key_data_ver == 1 ? 1 : 2);
135 for (i = 0; i < idx; i++) {
136 if ( from->key_data_length[i] ) {
137 to->key_data_contents[i] = malloc(from->key_data_length[i]);
138 if (to->key_data_contents[i] == NULL) {
139 for (i = 0; i < idx; i++) {
140 if (to->key_data_contents[i]) {
141 memset(to->key_data_contents[i], 0,
142 to->key_data_length[i]);
143 free(to->key_data_contents[i]);
148 memcpy(to->key_data_contents[i], from->key_data_contents[i],
149 from->key_data_length[i]);
155 static krb5_tl_data *dup_tl_data(krb5_tl_data *tl)
159 n = (krb5_tl_data *) malloc(sizeof(krb5_tl_data));
162 n->tl_data_contents = malloc(tl->tl_data_length);
163 if (n->tl_data_contents == NULL) {
167 memcpy(n->tl_data_contents, tl->tl_data_contents, tl->tl_data_length);
168 n->tl_data_type = tl->tl_data_type;
169 n->tl_data_length = tl->tl_data_length;
170 n->tl_data_next = NULL;
174 /* This is in lib/kdb/kdb_cpw.c, but is static */
175 static void cleanup_key_data(context, count, data)
176 krb5_context context;
178 krb5_key_data * data;
182 for (i = 0; i < count; i++)
183 for (j = 0; j < data[i].key_data_ver; j++)
184 if (data[i].key_data_length[j])
185 krb5_db_free(context, data[i].key_data_contents[j]);
186 krb5_db_free(context, data);
190 kadm5_create_principal(void *server_handle,
191 kadm5_principal_ent_t entry, long mask,
195 kadm5_create_principal_3(server_handle, entry, mask,
199 kadm5_create_principal_3(void *server_handle,
200 kadm5_principal_ent_t entry, long mask,
201 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
205 osa_princ_ent_rec adb;
206 kadm5_policy_ent_rec polent;
208 krb5_tl_data *tl_data_orig, *tl_data_tail;
210 kadm5_server_handle_t handle = server_handle;
211 krb5_keyblock *act_mkey;
214 CHECK_HANDLE(server_handle);
216 krb5_clear_error_message(handle->context);
219 * Argument sanity checking, and opening up the DB
221 if(!(mask & KADM5_PRINCIPAL) || (mask & KADM5_MOD_NAME) ||
222 (mask & KADM5_MOD_TIME) || (mask & KADM5_LAST_PWD_CHANGE) ||
223 (mask & KADM5_MKVNO) || (mask & KADM5_POLICY_CLR) ||
224 (mask & KADM5_AUX_ATTRIBUTES) || (mask & KADM5_KEY_DATA) ||
225 (mask & KADM5_LAST_SUCCESS) || (mask & KADM5_LAST_FAILED) ||
226 (mask & KADM5_FAIL_AUTH_COUNT))
227 return KADM5_BAD_MASK;
228 if((mask & ~ALL_PRINC_MASK))
229 return KADM5_BAD_MASK;
234 * Check to see if the principal exists
236 ret = kdb_get_entry(handle, entry->principal, &kdb, &adb);
239 case KADM5_UNK_PRINC:
242 kdb_free_entry(handle, &kdb, &adb);
248 memset(&kdb, 0, sizeof(krb5_db_entry));
249 memset(&adb, 0, sizeof(osa_princ_ent_rec));
252 * If a policy was specified, load it.
253 * If we can not find the one specified return an error
255 if ((mask & KADM5_POLICY)) {
256 if ((ret = kadm5_get_policy(handle->lhandle, entry->policy,
257 &polent)) != KADM5_OK) {
259 return KADM5_BAD_POLICY;
265 ret = passwd_check(handle, password, (mask & KADM5_POLICY),
266 &polent, entry->principal);
268 if (mask & KADM5_POLICY)
269 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
274 * Start populating the various DB fields, using the
275 * "defaults" for fields that were not specified by the
278 if ((ret = krb5_timeofday(handle->context, &now))) {
279 if (mask & KADM5_POLICY)
280 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
284 kdb.magic = KRB5_KDB_MAGIC_NUMBER;
285 kdb.len = KRB5_KDB_V1_BASE_LENGTH; /* gag me with a chainsaw */
287 if ((mask & KADM5_ATTRIBUTES))
288 kdb.attributes = entry->attributes;
290 kdb.attributes = handle->params.flags;
292 if ((mask & KADM5_MAX_LIFE))
293 kdb.max_life = entry->max_life;
295 kdb.max_life = handle->params.max_life;
297 if (mask & KADM5_MAX_RLIFE)
298 kdb.max_renewable_life = entry->max_renewable_life;
300 kdb.max_renewable_life = handle->params.max_rlife;
302 if ((mask & KADM5_PRINC_EXPIRE_TIME))
303 kdb.expiration = entry->princ_expire_time;
305 kdb.expiration = handle->params.expiration;
307 kdb.pw_expiration = 0;
308 if ((mask & KADM5_POLICY)) {
309 if(polent.pw_max_life)
310 kdb.pw_expiration = now + polent.pw_max_life;
312 kdb.pw_expiration = 0;
314 if ((mask & KADM5_PW_EXPIRATION))
315 kdb.pw_expiration = entry->pw_expiration;
317 kdb.last_success = 0;
319 kdb.fail_auth_count = 0;
321 /* this is kind of gross, but in order to free the tl data, I need
322 to free the entire kdb entry, and that will try to free the
325 if ((ret = kadm5_copy_principal(handle->context,
326 entry->principal, &(kdb.princ)))) {
327 if (mask & KADM5_POLICY)
328 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
332 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now))) {
333 krb5_db_free_principal(handle->context, &kdb, 1);
334 if (mask & KADM5_POLICY)
335 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
339 if (mask & KADM5_TL_DATA) {
340 /* splice entry->tl_data onto the front of kdb.tl_data */
341 tl_data_orig = kdb.tl_data;
342 for (tl_data_tail = entry->tl_data; tl_data_tail;
343 tl_data_tail = tl_data_tail->tl_data_next)
345 ret = krb5_dbe_update_tl_data(handle->context, &kdb, tl_data_tail);
348 krb5_db_free_principal(handle->context, &kdb, 1);
349 if (mask & KADM5_POLICY)
350 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
356 /* initialize the keys */
358 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
359 active_mkey_list, &act_kvno, &act_mkey);
361 krb5_db_free_principal(handle->context, &kdb, 1);
362 if (mask & KADM5_POLICY)
363 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
368 ret = krb5_dbe_cpw(handle->context, act_mkey,
369 n_ks_tuple?ks_tuple:handle->params.keysalts,
370 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
371 password, (mask & KADM5_KVNO)?entry->kvno:1,
374 /* Null password means create with random key (new in 1.8). */
375 ret = krb5_dbe_crk(handle->context, &master_keyblock,
376 n_ks_tuple?ks_tuple:handle->params.keysalts,
377 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
381 krb5_db_free_principal(handle->context, &kdb, 1);
382 if (mask & KADM5_POLICY)
383 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
387 /* Record the master key VNO used to encrypt this entry's keys */
388 ret = krb5_dbe_update_mkvno(handle->context, &kdb, act_kvno);
391 krb5_db_free_principal(handle->context, &kdb, 1);
392 if (mask & KADM5_POLICY)
393 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
397 /* populate the admin-server-specific fields. In the OV server,
398 this used to be in a separate database. Since there's already
399 marshalling code for the admin fields, to keep things simple,
400 I'm going to keep it, and make all the admin stuff occupy a
401 single tl_data record, */
403 adb.admin_history_kvno = hist_kvno;
404 if ((mask & KADM5_POLICY)) {
405 adb.aux_attributes = KADM5_POLICY;
407 /* this does *not* need to be strdup'ed, because adb is xdr */
408 /* encoded in osa_adb_create_princ, and not ever freed */
410 adb.policy = entry->policy;
413 /* increment the policy ref count, if any */
415 if ((mask & KADM5_POLICY)) {
416 polent.policy_refcnt++;
417 if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent,
420 krb5_db_free_principal(handle->context, &kdb, 1);
421 if (mask & KADM5_POLICY)
422 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
427 /* In all cases key and the principal data is set, let the database provider know */
428 kdb.mask = mask | KADM5_KEY_DATA | KADM5_PRINCIPAL ;
430 /* store the new db entry */
431 ret = kdb_put_entry(handle, &kdb, &adb);
433 krb5_db_free_principal(handle->context, &kdb, 1);
436 if ((mask & KADM5_POLICY)) {
437 /* decrement the policy ref count */
439 polent.policy_refcnt--;
441 * if this fails, there's nothing we can do anyway. the
442 * policy refcount wil be too high.
444 (void) kadm5_modify_policy_internal(handle->lhandle, &polent,
448 if (mask & KADM5_POLICY)
449 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
453 if (mask & KADM5_POLICY)
454 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
461 kadm5_delete_principal(void *server_handle, krb5_principal principal)
464 kadm5_policy_ent_rec polent;
466 osa_princ_ent_rec adb;
467 kadm5_server_handle_t handle = server_handle;
469 CHECK_HANDLE(server_handle);
471 krb5_clear_error_message(handle->context);
473 if (principal == NULL)
476 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
479 if ((adb.aux_attributes & KADM5_POLICY)) {
480 if ((ret = kadm5_get_policy(handle->lhandle,
481 adb.policy, &polent))
483 polent.policy_refcnt--;
484 if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent,
487 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
488 kdb_free_entry(handle, &kdb, &adb);
492 if ((ret = kadm5_free_policy_ent(handle->lhandle, &polent))) {
493 kdb_free_entry(handle, &kdb, &adb);
498 ret = kdb_delete_entry(handle, principal);
500 kdb_free_entry(handle, &kdb, &adb);
506 kadm5_modify_principal(void *server_handle,
507 kadm5_principal_ent_t entry, long mask)
510 kadm5_policy_ent_rec npol, opol;
511 int have_npol = 0, have_opol = 0;
513 krb5_tl_data *tl_data_orig;
514 osa_princ_ent_rec adb;
515 kadm5_server_handle_t handle = server_handle;
517 CHECK_HANDLE(server_handle);
519 krb5_clear_error_message(handle->context);
521 if((mask & KADM5_PRINCIPAL) || (mask & KADM5_LAST_PWD_CHANGE) ||
522 (mask & KADM5_MOD_TIME) || (mask & KADM5_MOD_NAME) ||
523 (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) ||
524 (mask & KADM5_KEY_DATA) || (mask & KADM5_LAST_SUCCESS) ||
525 (mask & KADM5_LAST_FAILED))
526 return KADM5_BAD_MASK;
527 if((mask & ~ALL_PRINC_MASK))
528 return KADM5_BAD_MASK;
529 if((mask & KADM5_POLICY) && (mask & KADM5_POLICY_CLR))
530 return KADM5_BAD_MASK;
531 if(entry == (kadm5_principal_ent_t) NULL)
533 if (mask & KADM5_TL_DATA) {
534 tl_data_orig = entry->tl_data;
535 while (tl_data_orig) {
536 if (tl_data_orig->tl_data_type < 256)
537 return KADM5_BAD_TL_TYPE;
538 tl_data_orig = tl_data_orig->tl_data_next;
542 ret = kdb_get_entry(handle, entry->principal, &kdb, &adb);
547 * This is pretty much the same as create ...
550 if ((mask & KADM5_POLICY)) {
551 /* get the new policy */
552 ret = kadm5_get_policy(handle->lhandle, entry->policy, &npol);
556 ret = KADM5_BAD_POLICY;
558 case KADM5_UNK_POLICY:
559 case KADM5_BAD_POLICY:
560 ret = KADM5_UNK_POLICY;
567 /* if we already have a policy, get it to decrement the refcnt */
568 if(adb.aux_attributes & KADM5_POLICY) {
569 /* ... but not if the old and new are the same */
570 if(strcmp(adb.policy, entry->policy)) {
571 ret = kadm5_get_policy(handle->lhandle,
575 case KADM5_BAD_POLICY:
576 case KADM5_UNK_POLICY:
580 opol.policy_refcnt--;
586 npol.policy_refcnt++;
588 } else npol.policy_refcnt++;
590 /* set us up to use the new policy */
591 adb.aux_attributes |= KADM5_POLICY;
594 adb.policy = strdup(entry->policy);
596 /* set pw_max_life based on new policy */
597 if (npol.pw_max_life) {
598 ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb,
599 &(kdb.pw_expiration));
602 kdb.pw_expiration += npol.pw_max_life;
604 kdb.pw_expiration = 0;
608 if ((mask & KADM5_POLICY_CLR) &&
609 (adb.aux_attributes & KADM5_POLICY)) {
610 ret = kadm5_get_policy(handle->lhandle, adb.policy, &opol);
613 case KADM5_BAD_POLICY:
614 case KADM5_UNK_POLICY:
623 adb.aux_attributes &= ~KADM5_POLICY;
624 kdb.pw_expiration = 0;
625 opol.policy_refcnt--;
633 if (((mask & KADM5_POLICY) || (mask & KADM5_POLICY_CLR)) &&
636 kadm5_modify_policy_internal(handle->lhandle, &opol,
637 KADM5_REF_COUNT))) ||
640 kadm5_modify_policy_internal(handle->lhandle, &npol,
644 if ((mask & KADM5_ATTRIBUTES))
645 kdb.attributes = entry->attributes;
646 if ((mask & KADM5_MAX_LIFE))
647 kdb.max_life = entry->max_life;
648 if ((mask & KADM5_PRINC_EXPIRE_TIME))
649 kdb.expiration = entry->princ_expire_time;
650 if (mask & KADM5_PW_EXPIRATION)
651 kdb.pw_expiration = entry->pw_expiration;
652 if (mask & KADM5_MAX_RLIFE)
653 kdb.max_renewable_life = entry->max_renewable_life;
655 if((mask & KADM5_KVNO)) {
656 for (i = 0; i < kdb.n_key_data; i++)
657 kdb.key_data[i].key_data_kvno = entry->kvno;
660 if (mask & KADM5_TL_DATA) {
663 /* may have to change the version number of the API. Updates the list with the given tl_data rather than over-writting */
665 for (tl = entry->tl_data; tl;
666 tl = tl->tl_data_next)
668 ret = krb5_dbe_update_tl_data(handle->context, &kdb, tl);
677 * Setting entry->fail_auth_count to 0 can be used to manually unlock
678 * an account. It is not possible to set fail_auth_count to any other
679 * value using kadmin.
681 if (mask & KADM5_FAIL_AUTH_COUNT) {
682 if (entry->fail_auth_count != 0) {
683 ret = KADM5_BAD_SERVER_PARAMS;
687 kdb.fail_auth_count = 0;
690 /* let the mask propagate to the database provider */
693 ret = kdb_put_entry(handle, &kdb, &adb);
699 ret2 = kadm5_free_policy_ent(handle->lhandle, &opol);
700 ret = ret ? ret : ret2;
703 ret2 = kadm5_free_policy_ent(handle->lhandle, &npol);
704 ret = ret ? ret : ret2;
706 kdb_free_entry(handle, &kdb, &adb);
711 kadm5_rename_principal(void *server_handle,
712 krb5_principal source, krb5_principal target)
715 osa_princ_ent_rec adb;
717 kadm5_server_handle_t handle = server_handle;
719 CHECK_HANDLE(server_handle);
721 krb5_clear_error_message(handle->context);
723 if (source == NULL || target == NULL)
726 if ((ret = kdb_get_entry(handle, target, &kdb, &adb)) == 0) {
727 kdb_free_entry(handle, &kdb, &adb);
731 if ((ret = kdb_get_entry(handle, source, &kdb, &adb)))
734 /* this is kinda gross, but unavoidable */
736 for (i=0; i<kdb.n_key_data; i++) {
737 if ((kdb.key_data[i].key_data_ver == 1) ||
738 (kdb.key_data[i].key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL)) {
739 ret = KADM5_NO_RENAME_SALT;
744 kadm5_free_principal(handle->context, kdb.princ);
745 ret = kadm5_copy_principal(handle->context, target, &kdb.princ);
747 kdb.princ = NULL; /* so freeing the dbe doesn't lose */
751 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
754 ret = kdb_delete_entry(handle, source);
757 kdb_free_entry(handle, &kdb, &adb);
762 kadm5_get_principal(void *server_handle, krb5_principal principal,
763 kadm5_principal_ent_t entry,
767 osa_princ_ent_rec adb;
768 krb5_error_code ret = 0;
771 kadm5_server_handle_t handle = server_handle;
773 CHECK_HANDLE(server_handle);
775 krb5_clear_error_message(handle->context);
778 * In version 1, all the defined fields are always returned.
779 * entry is a pointer to a kadm5_principal_ent_t_v1 that should be
780 * filled with allocated memory.
784 memset(entry, 0, sizeof(*entry));
786 if (principal == NULL)
789 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
792 if ((mask & KADM5_POLICY) &&
793 adb.policy && (adb.aux_attributes & KADM5_POLICY)) {
794 if ((entry->policy = strdup(adb.policy)) == NULL) {
800 if (mask & KADM5_AUX_ATTRIBUTES)
801 entry->aux_attributes = adb.aux_attributes;
803 if ((mask & KADM5_PRINCIPAL) &&
804 (ret = krb5_copy_principal(handle->context, kdb.princ,
805 &entry->principal))) {
809 if (mask & KADM5_PRINC_EXPIRE_TIME)
810 entry->princ_expire_time = kdb.expiration;
812 if ((mask & KADM5_LAST_PWD_CHANGE) &&
813 (ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb,
814 &(entry->last_pwd_change)))) {
818 if (mask & KADM5_PW_EXPIRATION)
819 entry->pw_expiration = kdb.pw_expiration;
820 if (mask & KADM5_MAX_LIFE)
821 entry->max_life = kdb.max_life;
823 /* this is a little non-sensical because the function returns two */
824 /* values that must be checked separately against the mask */
825 if ((mask & KADM5_MOD_NAME) || (mask & KADM5_MOD_TIME)) {
826 ret = krb5_dbe_lookup_mod_princ_data(handle->context, &kdb,
833 if (! (mask & KADM5_MOD_TIME))
835 if (! (mask & KADM5_MOD_NAME)) {
836 krb5_free_principal(handle->context, entry->principal);
837 entry->principal = NULL;
841 if (mask & KADM5_ATTRIBUTES)
842 entry->attributes = kdb.attributes;
844 if (mask & KADM5_KVNO)
845 for (entry->kvno = 0, i=0; i<kdb.n_key_data; i++)
846 if (kdb.key_data[i].key_data_kvno > entry->kvno)
847 entry->kvno = kdb.key_data[i].key_data_kvno;
849 ret = krb5_dbe_lookup_mkvno(handle->context, &kdb, &entry->mkvno);
853 if (mask & KADM5_MAX_RLIFE)
854 entry->max_renewable_life = kdb.max_renewable_life;
855 if (mask & KADM5_LAST_SUCCESS)
856 entry->last_success = kdb.last_success;
857 if (mask & KADM5_LAST_FAILED)
858 entry->last_failed = kdb.last_failed;
859 if (mask & KADM5_FAIL_AUTH_COUNT)
860 entry->fail_auth_count = kdb.fail_auth_count;
861 if (mask & KADM5_TL_DATA) {
862 krb5_tl_data *tl, *tl2;
864 entry->tl_data = NULL;
868 if (tl->tl_data_type > 255) {
869 if ((tl2 = dup_tl_data(tl)) == NULL) {
873 tl2->tl_data_next = entry->tl_data;
874 entry->tl_data = tl2;
878 tl = tl->tl_data_next;
881 if (mask & KADM5_KEY_DATA) {
882 entry->n_key_data = kdb.n_key_data;
883 if(entry->n_key_data) {
884 entry->key_data = malloc(entry->n_key_data*sizeof(krb5_key_data));
885 if (entry->key_data == NULL) {
890 entry->key_data = NULL;
892 for (i = 0; i < entry->n_key_data; i++)
893 ret = krb5_copy_key_data_contents(handle->context,
895 &entry->key_data[i]);
903 if (ret && entry->principal) {
904 krb5_free_principal(handle->context, entry->principal);
905 entry->principal = NULL;
907 kdb_free_entry(handle, &kdb, &adb);
913 * Function: check_pw_reuse
915 * Purpose: Check if a key appears in a list of keys, in order to
916 * enforce password history.
920 * context (r) the krb5 context
921 * hist_keyblock (r) the key that hist_key_data is
923 * n_new_key_data (r) length of new_key_data
924 * new_key_data (r) keys to check against
925 * pw_hist_data, encrypted in hist_keyblock
926 * n_pw_hist_data (r) length of pw_hist_data
927 * pw_hist_data (r) passwords to check new_key_data against
930 * For each new_key in new_key_data:
931 * decrypt new_key with the master_keyblock
932 * for each password in pw_hist_data:
933 * for each hist_key in password:
934 * decrypt hist_key with hist_keyblock
935 * compare the new_key and hist_key
937 * Returns krb5 errors, KADM5_PASS_RESUSE if a key in
938 * new_key_data is the same as a key in pw_hist_data, or 0.
941 check_pw_reuse(krb5_context context,
943 krb5_keyblock *hist_keyblock,
944 int n_new_key_data, krb5_key_data *new_key_data,
945 unsigned int n_pw_hist_data, osa_pw_hist_ent *pw_hist_data)
948 krb5_keyblock newkey, histkey;
951 for (x = 0; x < n_new_key_data; x++) {
952 ret = krb5_dbekd_decrypt_key_data(context,
958 for (y = 0; y < n_pw_hist_data; y++) {
959 for (z = 0; z < pw_hist_data[y].n_key_data; z++) {
960 ret = krb5_dbekd_decrypt_key_data(context,
962 &pw_hist_data[y].key_data[z],
967 if ((newkey.length == histkey.length) &&
968 (newkey.enctype == histkey.enctype) &&
969 (memcmp(newkey.contents, histkey.contents,
970 histkey.length) == 0)) {
971 krb5_free_keyblock_contents(context, &histkey);
972 krb5_free_keyblock_contents(context, &newkey);
974 return(KADM5_PASS_REUSE);
976 krb5_free_keyblock_contents(context, &histkey);
979 krb5_free_keyblock_contents(context, &newkey);
986 * Function: create_history_entry
988 * Purpose: Creates a password history entry from an array of
993 * context (r) krb5_context to use
994 * n_key_data (r) number of elements in key_data
995 * key_data (r) keys to add to the history entry
996 * hist (w) history entry to fill in
1000 * hist->key_data is allocated to store n_key_data key_datas. Each
1001 * element of key_data is decrypted with master_keyblock, re-encrypted
1002 * in hist_key, and added to hist->key_data. hist->n_key_data is
1003 * set to n_key_data.
1006 int create_history_entry(krb5_context context, krb5_keyblock *mkey, int n_key_data,
1007 krb5_key_data *key_data, osa_pw_hist_ent *hist)
1013 hist->key_data = (krb5_key_data*)malloc(n_key_data*sizeof(krb5_key_data));
1014 if (hist->key_data == NULL)
1016 memset(hist->key_data, 0, n_key_data*sizeof(krb5_key_data));
1018 for (i = 0; i < n_key_data; i++) {
1019 ret = krb5_dbekd_decrypt_key_data(context,
1026 ret = krb5_dbekd_encrypt_key_data(context, &hist_key,
1028 key_data[i].key_data_kvno,
1029 &hist->key_data[i]);
1033 krb5_free_keyblock_contents(context, &key);
1034 /* krb5_free_keysalt(context, &salt); */
1037 hist->n_key_data = n_key_data;
1042 void free_history_entry(krb5_context context, osa_pw_hist_ent *hist)
1046 for (i = 0; i < hist->n_key_data; i++)
1047 krb5_free_key_data_contents(context, &hist->key_data[i]);
1048 free(hist->key_data);
1052 * Function: add_to_history
1054 * Purpose: Adds a password to a principal's password history.
1058 * context (r) krb5_context to use
1059 * adb (r/w) admin principal entry to add keys to
1060 * pol (r) adb's policy
1061 * pw (r) keys for the password to add to adb's key history
1065 * add_to_history adds a single password to adb's password history.
1066 * pw contains n_key_data keys in its key_data, in storage should be
1067 * allocated but not freed by the caller (XXX blech!).
1069 * This function maintains adb->old_keys as a circular queue. It
1070 * starts empty, and grows each time this function is called until it
1071 * is pol->pw_history_num items long. adb->old_key_len holds the
1072 * number of allocated entries in the array, and must therefore be [0,
1073 * pol->pw_history_num). adb->old_key_next is the index into the
1074 * array where the next element should be written, and must be [0,
1075 * adb->old_key_len).
1077 static kadm5_ret_t add_to_history(krb5_context context,
1078 osa_princ_ent_t adb,
1079 kadm5_policy_ent_t pol,
1080 osa_pw_hist_ent *pw)
1082 osa_pw_hist_ent *histp;
1084 unsigned int i, knext, nkeys;
1086 nhist = pol->pw_history_num;
1087 /* A history of 1 means just check the current password */
1091 nkeys = adb->old_key_len;
1092 knext = adb->old_key_next;
1093 /* resize the adb->old_keys array if necessary */
1094 if (nkeys + 1 < nhist) {
1095 if (adb->old_keys == NULL) {
1096 adb->old_keys = (osa_pw_hist_ent *)
1097 malloc((nkeys + 1) * sizeof (osa_pw_hist_ent));
1099 adb->old_keys = (osa_pw_hist_ent *)
1100 realloc(adb->old_keys,
1101 (nkeys + 1) * sizeof (osa_pw_hist_ent));
1103 if (adb->old_keys == NULL)
1106 memset(&adb->old_keys[nkeys], 0, sizeof(osa_pw_hist_ent));
1107 nkeys = ++adb->old_key_len;
1109 * To avoid losing old keys, shift forward each entry after
1112 for (i = nkeys - 1; i > knext; i--) {
1113 adb->old_keys[i] = adb->old_keys[i - 1];
1115 memset(&adb->old_keys[knext], 0, sizeof(osa_pw_hist_ent));
1116 } else if (nkeys + 1 > nhist) {
1118 * The policy must have changed! Shrink the array.
1119 * Can't simply realloc() down, since it might be wrapped.
1120 * To understand the arithmetic below, note that we are
1121 * copying into new positions 0 .. N-1 from old positions
1122 * old_key_next-N .. old_key_next-1, modulo old_key_len,
1123 * where N = pw_history_num - 1 is the length of the
1124 * shortened list. Matt Crawford, FNAL
1127 * M = adb->old_key_len, N = pol->pw_history_num - 1
1129 * tmp[0] .. tmp[N-1] = old[(knext-N)%M] .. old[(knext-1)%M]
1134 tmp = (osa_pw_hist_ent *)
1135 malloc((nhist - 1) * sizeof (osa_pw_hist_ent));
1138 for (i = 0; i < nhist - 1; i++) {
1140 * Add nkeys once before taking remainder to avoid
1143 j = (i + nkeys + knext - (nhist - 1)) % nkeys;
1144 tmp[i] = adb->old_keys[j];
1146 /* Now free the ones we don't keep (the oldest ones) */
1147 for (i = 0; i < nkeys - (nhist - 1); i++) {
1148 j = (i + nkeys + knext) % nkeys;
1149 histp = &adb->old_keys[j];
1150 for (j = 0; j < histp->n_key_data; j++) {
1151 krb5_free_key_data_contents(context, &histp->key_data[j]);
1153 free(histp->key_data);
1155 free(adb->old_keys);
1156 adb->old_keys = tmp;
1157 nkeys = adb->old_key_len = nhist - 1;
1158 knext = adb->old_key_next = 0;
1162 * If nhist decreased since the last password change, and nkeys+1
1163 * is less than the previous nhist, it is possible for knext to
1164 * index into unallocated space. This condition would not be
1165 * caught by the resizing code above.
1167 if (knext + 1 > nkeys)
1168 knext = adb->old_key_next = 0;
1169 /* free the old pw history entry if it contains data */
1170 histp = &adb->old_keys[knext];
1171 for (i = 0; i < histp->n_key_data; i++)
1172 krb5_free_key_data_contents(context, &histp->key_data[i]);
1173 free(histp->key_data);
1175 /* store the new entry */
1176 adb->old_keys[knext] = *pw;
1178 /* update the next pointer */
1179 if (++adb->old_key_next == nhist - 1)
1180 adb->old_key_next = 0;
1185 /* FIXME: don't use global variable for this */
1186 krb5_boolean use_password_server = 0;
1188 #ifdef USE_PASSWORD_SERVER
1190 kadm5_use_password_server (void)
1192 return use_password_server;
1197 kadm5_set_use_password_server (void)
1199 use_password_server = 1;
1202 #ifdef USE_PASSWORD_SERVER
1205 * kadm5_launch_task () runs a program (task_path) to synchronize the
1206 * Apple password server with the Kerberos database. Password server
1207 * programs can receive arguments on the command line (task_argv)
1208 * and a block of data via stdin (data_buffer).
1210 * Because a failure to communicate with the tool results in the
1211 * password server falling out of sync with the database,
1212 * kadm5_launch_task() always fails if it can't talk to the tool.
1216 kadm5_launch_task (krb5_context context,
1217 const char *task_path, char * const task_argv[],
1223 ret = pipe (data_pipe);
1228 pid_t pid = fork ();
1231 close (data_pipe[0]);
1232 close (data_pipe[1]);
1233 } else if (pid == 0) {
1236 if (dup2 (data_pipe[0], STDIN_FILENO) == -1)
1239 close (data_pipe[0]);
1240 close (data_pipe[1]);
1242 execv (task_path, task_argv);
1244 _exit (1); /* Fail if execv fails */
1251 close (data_pipe[0]);
1253 /* Write out the buffer to the child, add \n */
1255 if (krb5_net_write (context, data_pipe[1], buffer, strlen (buffer)) < 0
1256 || krb5_net_write (context, data_pipe[1], "\n", 1) < 0)
1258 /* kill the child to make sure waitpid() won't hang later */
1260 kill (pid, SIGKILL);
1263 close (data_pipe[1]);
1265 waitpid (pid, &status, 0);
1268 if (WIFEXITED (status)) {
1269 /* child read password and exited. Check the return value. */
1270 if ((WEXITSTATUS (status) != 0) && (WEXITSTATUS (status) != 252)) {
1271 ret = KRB5KDC_ERR_POLICY; /* password change rejected */
1274 /* child read password but crashed or was killed */
1275 ret = KRB5KRB_ERR_GENERIC; /* FIXME: better error */
1287 kadm5_chpass_principal(void *server_handle,
1288 krb5_principal principal, char *password)
1291 kadm5_chpass_principal_3(server_handle, principal, FALSE,
1296 kadm5_chpass_principal_3(void *server_handle,
1297 krb5_principal principal, krb5_boolean keepold,
1298 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1302 kadm5_policy_ent_rec pol;
1303 osa_princ_ent_rec adb;
1304 krb5_db_entry kdb, kdb_save;
1305 int ret, ret2, last_pwd, hist_added;
1307 kadm5_server_handle_t handle = server_handle;
1308 osa_pw_hist_ent hist;
1309 krb5_keyblock *act_mkey;
1312 CHECK_HANDLE(server_handle);
1314 krb5_clear_error_message(handle->context);
1317 memset(&hist, 0, sizeof(hist));
1319 if (principal == NULL || password == NULL)
1321 if ((krb5_principal_compare(handle->context,
1322 principal, hist_princ)) == TRUE)
1323 return KADM5_PROTECT_PRINCIPAL;
1325 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1328 /* we are going to need the current keys after the new keys are set */
1329 if ((ret = kdb_get_entry(handle, principal, &kdb_save, NULL))) {
1330 kdb_free_entry(handle, &kdb, &adb);
1334 if ((adb.aux_attributes & KADM5_POLICY)) {
1335 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &pol)))
1340 if ((ret = passwd_check(handle, password, adb.aux_attributes &
1341 KADM5_POLICY, &pol, principal)))
1344 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
1345 active_mkey_list, &act_kvno, &act_mkey);
1349 ret = krb5_dbe_cpw(handle->context, act_mkey,
1350 n_ks_tuple?ks_tuple:handle->params.keysalts,
1351 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
1352 password, 0 /* increment kvno */,
1357 ret = krb5_dbe_update_mkvno(handle->context, &kdb, act_kvno);
1361 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1363 ret = krb5_timeofday(handle->context, &now);
1367 if ((adb.aux_attributes & KADM5_POLICY)) {
1368 /* the policy was loaded before */
1370 ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1377 * The spec says this check is overridden if the caller has
1378 * modify privilege. The admin server therefore makes this
1379 * check itself (in chpass_principal_wrapper, misc.c). A
1380 * local caller implicitly has all authorization bits.
1382 if ((now - last_pwd) < pol.pw_min_life &&
1383 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1384 ret = KADM5_PASS_TOOSOON;
1389 ret = create_history_entry(handle->context,
1391 kdb_save.n_key_data,
1392 kdb_save.key_data, &hist);
1396 ret = check_pw_reuse(handle->context, act_mkey, &hist_key,
1397 kdb.n_key_data, kdb.key_data,
1402 if (pol.pw_history_num > 1) {
1403 if (adb.admin_history_kvno != hist_kvno) {
1404 ret = KADM5_BAD_HIST_KEY;
1408 ret = check_pw_reuse(handle->context, act_mkey, &hist_key,
1409 kdb.n_key_data, kdb.key_data,
1410 adb.old_key_len, adb.old_keys);
1414 ret = add_to_history(handle->context, &adb, &pol, &hist);
1420 if (pol.pw_max_life)
1421 kdb.pw_expiration = now + pol.pw_max_life;
1423 kdb.pw_expiration = 0;
1425 kdb.pw_expiration = 0;
1428 #ifdef USE_PASSWORD_SERVER
1429 if (kadm5_use_password_server () &&
1430 (krb5_princ_size (handle->context, principal) == 1)) {
1431 krb5_data *princ = krb5_princ_component (handle->context, principal, 0);
1432 const char *path = "/usr/sbin/mkpassdb";
1433 char *argv[] = { "mkpassdb", "-setpassword", NULL, NULL };
1434 char *pstring = NULL;
1437 pstring = malloc ((princ->length + 1) * sizeof (char));
1438 if (pstring == NULL) { ret = ENOMEM; }
1442 memcpy (pstring, princ->data, princ->length);
1443 pstring [princ->length] = '\0';
1446 ret = kadm5_launch_task (handle->context, path, argv, password);
1449 if (pstring != NULL)
1457 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
1461 /* unlock principal on this KDC */
1462 kdb.fail_auth_count = 0;
1464 /* key data and attributes changed, let the database provider know */
1465 kdb.mask = KADM5_KEY_DATA | KADM5_ATTRIBUTES |
1466 KADM5_FAIL_AUTH_COUNT;
1467 /* | KADM5_CPW_FUNCTION */
1469 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1474 if (!hist_added && hist.key_data)
1475 free_history_entry(handle->context, &hist);
1476 kdb_free_entry(handle, &kdb, &adb);
1477 kdb_free_entry(handle, &kdb_save, NULL);
1478 krb5_db_free_principal(handle->context, &kdb, 1);
1480 if (have_pol && (ret2 = kadm5_free_policy_ent(handle->lhandle, &pol))
1488 kadm5_randkey_principal(void *server_handle,
1489 krb5_principal principal,
1490 krb5_keyblock **keyblocks,
1494 kadm5_randkey_principal_3(server_handle, principal,
1499 kadm5_randkey_principal_3(void *server_handle,
1500 krb5_principal principal,
1501 krb5_boolean keepold,
1502 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1503 krb5_keyblock **keyblocks,
1507 osa_princ_ent_rec adb;
1509 kadm5_policy_ent_rec pol;
1510 int ret, last_pwd, have_pol = 0;
1511 kadm5_server_handle_t handle = server_handle;
1512 krb5_keyblock *act_mkey;
1517 CHECK_HANDLE(server_handle);
1519 krb5_clear_error_message(handle->context);
1521 if (principal == NULL)
1523 if (hist_princ && /* this will be NULL when initializing the databse */
1524 ((krb5_principal_compare(handle->context,
1525 principal, hist_princ)) == TRUE))
1526 return KADM5_PROTECT_PRINCIPAL;
1528 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1531 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
1532 active_mkey_list, NULL, &act_mkey);
1536 ret = krb5_dbe_crk(handle->context, act_mkey,
1537 n_ks_tuple?ks_tuple:handle->params.keysalts,
1538 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
1544 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1546 ret = krb5_timeofday(handle->context, &now);
1550 if ((adb.aux_attributes & KADM5_POLICY)) {
1551 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1556 ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1563 * The spec says this check is overridden if the caller has
1564 * modify privilege. The admin server therefore makes this
1565 * check itself (in chpass_principal_wrapper, misc.c). A
1566 * local caller implicitly has all authorization bits.
1568 if((now - last_pwd) < pol.pw_min_life &&
1569 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1570 ret = KADM5_PASS_TOOSOON;
1575 if(pol.pw_history_num > 1) {
1576 if(adb.admin_history_kvno != hist_kvno) {
1577 ret = KADM5_BAD_HIST_KEY;
1581 ret = check_pw_reuse(handle->context, act_mkey, &hist_key,
1582 kdb.n_key_data, kdb.key_data,
1583 adb.old_key_len, adb.old_keys);
1587 if (pol.pw_max_life)
1588 kdb.pw_expiration = now + pol.pw_max_life;
1590 kdb.pw_expiration = 0;
1592 kdb.pw_expiration = 0;
1595 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
1599 /* unlock principal on this KDC */
1600 kdb.fail_auth_count = 0;
1603 ret = decrypt_key_data(handle->context, act_mkey,
1604 kdb.n_key_data, kdb.key_data,
1610 /* key data changed, let the database provider know */
1611 kdb.mask = KADM5_KEY_DATA | KADM5_FAIL_AUTH_COUNT;
1612 /* | KADM5_RANDKEY_USED */;
1614 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1619 kdb_free_entry(handle, &kdb, &adb);
1621 kadm5_free_policy_ent(handle->lhandle, &pol);
1627 * kadm5_setv4key_principal:
1629 * Set only ONE key of the principal, removing all others. This key
1630 * must have the DES_CBC_CRC enctype and is entered as having the
1631 * krb4 salttype. This is to enable things like kadmind4 to work.
1634 kadm5_setv4key_principal(void *server_handle,
1635 krb5_principal principal,
1636 krb5_keyblock *keyblock)
1639 osa_princ_ent_rec adb;
1641 kadm5_policy_ent_rec pol;
1642 krb5_keysalt keysalt;
1643 int i, k, kvno, ret, have_pol = 0;
1647 kadm5_server_handle_t handle = server_handle;
1648 krb5_key_data tmp_key_data;
1649 krb5_keyblock *act_mkey;
1651 memset( &tmp_key_data, 0, sizeof(tmp_key_data));
1653 CHECK_HANDLE(server_handle);
1655 krb5_clear_error_message(handle->context);
1657 if (principal == NULL || keyblock == NULL)
1659 if (hist_princ && /* this will be NULL when initializing the databse */
1660 ((krb5_principal_compare(handle->context,
1661 principal, hist_princ)) == TRUE))
1662 return KADM5_PROTECT_PRINCIPAL;
1664 if (keyblock->enctype != ENCTYPE_DES_CBC_CRC)
1665 return KADM5_SETV4KEY_INVAL_ENCTYPE;
1667 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1670 for (kvno = 0, i=0; i<kdb.n_key_data; i++)
1671 if (kdb.key_data[i].key_data_kvno > kvno)
1672 kvno = kdb.key_data[i].key_data_kvno;
1674 if (kdb.key_data != NULL)
1675 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
1677 kdb.key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, sizeof(krb5_key_data));
1678 if (kdb.key_data == NULL)
1680 memset(kdb.key_data, 0, sizeof(krb5_key_data));
1682 keysalt.type = KRB5_KDB_SALTTYPE_V4;
1683 /* XXX data.magic? */
1684 keysalt.data.length = 0;
1685 keysalt.data.data = NULL;
1687 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
1688 active_mkey_list, NULL, &act_mkey);
1692 /* use tmp_key_data as temporary location and reallocate later */
1693 ret = krb5_dbekd_encrypt_key_data(handle->context, act_mkey,
1694 keyblock, &keysalt, kvno + 1,
1700 for (k = 0; k < tmp_key_data.key_data_ver; k++) {
1701 kdb.key_data->key_data_type[k] = tmp_key_data.key_data_type[k];
1702 kdb.key_data->key_data_length[k] = tmp_key_data.key_data_length[k];
1703 if (tmp_key_data.key_data_contents[k]) {
1704 kdb.key_data->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]);
1705 if (kdb.key_data->key_data_contents[k] == NULL) {
1706 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
1707 kdb.key_data = NULL;
1712 memcpy (kdb.key_data->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
1714 memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
1715 free (tmp_key_data.key_data_contents[k]);
1716 tmp_key_data.key_data_contents[k] = NULL;
1722 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1724 ret = krb5_timeofday(handle->context, &now);
1728 if ((adb.aux_attributes & KADM5_POLICY)) {
1729 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1736 * The spec says this check is overridden if the caller has
1737 * modify privilege. The admin server therefore makes this
1738 * check itself (in chpass_principal_wrapper, misc.c). A
1739 * local caller implicitly has all authorization bits.
1741 if (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1744 if((now - last_pwd) < pol.pw_min_life &&
1745 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1746 ret = KADM5_PASS_TOOSOON;
1752 * Should we be checking/updating pw history here?
1754 if(pol.pw_history_num > 1) {
1755 if(adb.admin_history_kvno != hist_kvno) {
1756 ret = KADM5_BAD_HIST_KEY;
1760 if (ret = check_pw_reuse(handle->context,
1762 kdb.n_key_data, kdb.key_data,
1763 adb.old_key_len, adb.old_keys))
1768 if (pol.pw_max_life)
1769 kdb.pw_expiration = now + pol.pw_max_life;
1771 kdb.pw_expiration = 0;
1773 kdb.pw_expiration = 0;
1776 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
1780 /* unlock principal on this KDC */
1781 kdb.fail_auth_count = 0;
1783 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1788 for (i = 0; i < tmp_key_data.key_data_ver; i++) {
1789 if (tmp_key_data.key_data_contents[i]) {
1790 memset (tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]);
1791 free (tmp_key_data.key_data_contents[i]);
1795 kdb_free_entry(handle, &kdb, &adb);
1797 kadm5_free_policy_ent(handle->lhandle, &pol);
1803 kadm5_setkey_principal(void *server_handle,
1804 krb5_principal principal,
1805 krb5_keyblock *keyblocks,
1809 kadm5_setkey_principal_3(server_handle, principal,
1815 kadm5_setkey_principal_3(void *server_handle,
1816 krb5_principal principal,
1817 krb5_boolean keepold,
1818 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1819 krb5_keyblock *keyblocks,
1823 osa_princ_ent_rec adb;
1825 kadm5_policy_ent_rec pol;
1826 krb5_key_data *old_key_data;
1828 int i, j, k, kvno, ret, have_pol = 0;
1832 kadm5_server_handle_t handle = server_handle;
1833 krb5_boolean similar;
1834 krb5_keysalt keysalt;
1835 krb5_key_data tmp_key_data;
1836 krb5_key_data *tptr;
1837 krb5_keyblock *act_mkey;
1839 CHECK_HANDLE(server_handle);
1841 krb5_clear_error_message(handle->context);
1843 if (principal == NULL || keyblocks == NULL)
1845 if (hist_princ && /* this will be NULL when initializing the databse */
1846 ((krb5_principal_compare(handle->context,
1847 principal, hist_princ)) == TRUE))
1848 return KADM5_PROTECT_PRINCIPAL;
1850 for (i = 0; i < n_keys; i++) {
1851 for (j = i+1; j < n_keys; j++) {
1852 if ((ret = krb5_c_enctype_compare(handle->context,
1853 keyblocks[i].enctype,
1854 keyblocks[j].enctype,
1859 if (ks_tuple[i].ks_salttype == ks_tuple[j].ks_salttype)
1860 return KADM5_SETKEY_DUP_ENCTYPES;
1862 return KADM5_SETKEY_DUP_ENCTYPES;
1867 if (n_ks_tuple && n_ks_tuple != n_keys)
1868 return KADM5_SETKEY3_ETYPE_MISMATCH;
1870 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1873 for (kvno = 0, i=0; i<kdb.n_key_data; i++)
1874 if (kdb.key_data[i].key_data_kvno > kvno)
1875 kvno = kdb.key_data[i].key_data_kvno;
1878 old_key_data = kdb.key_data;
1879 n_old_keys = kdb.n_key_data;
1881 if (kdb.key_data != NULL)
1882 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
1884 old_key_data = NULL;
1887 kdb.key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, (n_keys+n_old_keys)
1888 *sizeof(krb5_key_data));
1889 if (kdb.key_data == NULL) {
1894 memset(kdb.key_data, 0, (n_keys+n_old_keys)*sizeof(krb5_key_data));
1897 for (i = 0; i < n_keys; i++) {
1899 keysalt.type = ks_tuple[i].ks_salttype;
1900 keysalt.data.length = 0;
1901 keysalt.data.data = NULL;
1902 if (ks_tuple[i].ks_enctype != keyblocks[i].enctype) {
1903 ret = KADM5_SETKEY3_ETYPE_MISMATCH;
1907 memset (&tmp_key_data, 0, sizeof(tmp_key_data));
1909 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
1910 active_mkey_list, NULL, &act_mkey);
1914 ret = krb5_dbekd_encrypt_key_data(handle->context,
1917 n_ks_tuple ? &keysalt : NULL,
1923 tptr = &kdb.key_data[i];
1924 tptr->key_data_ver = tmp_key_data.key_data_ver;
1925 tptr->key_data_kvno = tmp_key_data.key_data_kvno;
1926 for (k = 0; k < tmp_key_data.key_data_ver; k++) {
1927 tptr->key_data_type[k] = tmp_key_data.key_data_type[k];
1928 tptr->key_data_length[k] = tmp_key_data.key_data_length[k];
1929 if (tmp_key_data.key_data_contents[k]) {
1930 tptr->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]);
1931 if (tptr->key_data_contents[k] == NULL) {
1933 for (i1 = k; i1 < tmp_key_data.key_data_ver; i1++) {
1934 if (tmp_key_data.key_data_contents[i1]) {
1935 memset (tmp_key_data.key_data_contents[i1], 0, tmp_key_data.key_data_length[i1]);
1936 free (tmp_key_data.key_data_contents[i1]);
1943 memcpy (tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
1945 memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
1946 free (tmp_key_data.key_data_contents[k]);
1947 tmp_key_data.key_data_contents[k] = NULL;
1953 /* copy old key data if necessary */
1954 for (i = 0; i < n_old_keys; i++) {
1955 kdb.key_data[i+n_keys] = old_key_data[i];
1956 memset(&old_key_data[i], 0, sizeof (krb5_key_data));
1961 krb5_db_free(handle->context, old_key_data);
1963 /* assert(kdb.n_key_data == n_keys + n_old_keys) */
1964 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1966 if ((ret = krb5_timeofday(handle->context, &now)))
1969 if ((adb.aux_attributes & KADM5_POLICY)) {
1970 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1977 * The spec says this check is overridden if the caller has
1978 * modify privilege. The admin server therefore makes this
1979 * check itself (in chpass_principal_wrapper, misc.c). A
1980 * local caller implicitly has all authorization bits.
1982 if (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1985 if((now - last_pwd) < pol.pw_min_life &&
1986 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1987 ret = KADM5_PASS_TOOSOON;
1993 * Should we be checking/updating pw history here?
1995 if (pol.pw_history_num > 1) {
1996 if(adb.admin_history_kvno != hist_kvno) {
1997 ret = KADM5_BAD_HIST_KEY;
2001 if (ret = check_pw_reuse(handle->context,
2003 kdb.n_key_data, kdb.key_data,
2004 adb.old_key_len, adb.old_keys))
2009 if (pol.pw_max_life)
2010 kdb.pw_expiration = now + pol.pw_max_life;
2012 kdb.pw_expiration = 0;
2014 kdb.pw_expiration = 0;
2017 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now)))
2020 /* unlock principal on this KDC */
2021 kdb.fail_auth_count = 0;
2023 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
2028 kdb_free_entry(handle, &kdb, &adb);
2030 kadm5_free_policy_ent(handle->lhandle, &pol);
2036 * Return the list of keys like kadm5_randkey_principal,
2037 * but don't modify the principal.
2040 kadm5_get_principal_keys(void *server_handle /* IN */,
2041 krb5_principal principal /* IN */,
2042 krb5_keyblock **keyblocks /* OUT */,
2043 int *n_keys /* OUT */)
2046 osa_princ_ent_rec adb;
2048 kadm5_server_handle_t handle = server_handle;
2049 krb5_keyblock *mkey_ptr;
2054 CHECK_HANDLE(server_handle);
2056 if (principal == NULL)
2059 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
2063 if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist, &kdb,
2065 krb5_keylist_node *tmp_mkey_list;
2066 /* try refreshing master key list */
2067 /* XXX it would nice if we had the mkvno here for optimization */
2068 if (krb5_db_fetch_mkey_list(handle->context, master_princ,
2069 &master_keyblock, 0,
2070 &tmp_mkey_list) == 0) {
2071 krb5_dbe_free_key_list(handle->context, master_keylist);
2072 master_keylist = tmp_mkey_list;
2073 if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist,
2074 &kdb, &mkey_ptr))) {
2082 ret = decrypt_key_data(handle->context, mkey_ptr,
2083 kdb.n_key_data, kdb.key_data,
2091 kdb_free_entry(handle, &kdb, &adb);
2098 * Allocate an array of n_key_data krb5_keyblocks, fill in each
2099 * element with the results of decrypting the nth key in key_data with
2100 * mkey, and if n_keys is not NULL fill it in with the
2101 * number of keys decrypted.
2103 static int decrypt_key_data(krb5_context context, krb5_keyblock *mkey,
2104 int n_key_data, krb5_key_data *key_data,
2105 krb5_keyblock **keyblocks, int *n_keys)
2107 krb5_keyblock *keys;
2110 keys = (krb5_keyblock *) malloc(n_key_data*sizeof(krb5_keyblock));
2113 memset(keys, 0, n_key_data*sizeof(krb5_keyblock));
2115 for (i = 0; i < n_key_data; i++) {
2116 ret = krb5_dbekd_decrypt_key_data(context, mkey,
2120 for (; i >= 0; i--) {
2121 if (keys[i].contents) {
2122 memset (keys[i].contents, 0, keys[i].length);
2123 free( keys[i].contents );
2127 memset(keys, 0, n_key_data*sizeof(krb5_keyblock));
2135 *n_keys = n_key_data;
2141 * Function: kadm5_decrypt_key
2143 * Purpose: Retrieves and decrypts a principal key.
2147 * server_handle (r) kadm5 handle
2148 * entry (r) principal retrieved with kadm5_get_principal
2149 * ktype (r) enctype to search for, or -1 to ignore
2150 * stype (r) salt type to search for, or -1 to ignore
2151 * kvno (r) kvno to search for, -1 for max, 0 for max
2152 * only if it also matches ktype and stype
2153 * keyblock (w) keyblock to fill in
2154 * keysalt (w) keysalt to fill in, or NULL
2155 * kvnop (w) kvno to fill in, or NULL
2157 * Effects: Searches the key_data array of entry, which must have been
2158 * retrived with kadm5_get_principal with the KADM5_KEY_DATA mask, to
2159 * find a key with a specified enctype, salt type, and kvno in a
2160 * principal entry. If not found, return ENOENT. Otherwise, decrypt
2161 * it with the master key, and return the key in keyblock, the salt
2162 * in salttype, and the key version number in kvno.
2164 * If ktype or stype is -1, it is ignored for the search. If kvno is
2165 * -1, ktype and stype are ignored and the key with the max kvno is
2166 * returned. If kvno is 0, only the key with the max kvno is returned
2167 * and only if it matches the ktype and stype; otherwise, ENOENT is
2170 kadm5_ret_t kadm5_decrypt_key(void *server_handle,
2171 kadm5_principal_ent_t entry, krb5_int32
2172 ktype, krb5_int32 stype, krb5_int32
2173 kvno, krb5_keyblock *keyblock,
2174 krb5_keysalt *keysalt, int *kvnop)
2176 kadm5_server_handle_t handle = server_handle;
2177 krb5_db_entry dbent;
2178 krb5_key_data *key_data;
2179 krb5_keyblock *mkey_ptr;
2182 CHECK_HANDLE(server_handle);
2184 if (entry->n_key_data == 0 || entry->key_data == NULL)
2187 /* find_enctype only uses these two fields */
2188 dbent.n_key_data = entry->n_key_data;
2189 dbent.key_data = entry->key_data;
2190 if ((ret = krb5_dbe_find_enctype(handle->context, &dbent, ktype,
2191 stype, kvno, &key_data)))
2194 /* find_mkey only uses this field */
2195 dbent.tl_data = entry->tl_data;
2196 if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist, &dbent,
2198 krb5_keylist_node *tmp_mkey_list;
2199 /* try refreshing master key list */
2200 /* XXX it would nice if we had the mkvno here for optimization */
2201 if (krb5_db_fetch_mkey_list(handle->context, master_princ,
2202 &master_keyblock, 0, &tmp_mkey_list) == 0) {
2203 krb5_dbe_free_key_list(handle->context, master_keylist);
2204 master_keylist = tmp_mkey_list;
2205 if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist,
2206 &dbent, &mkey_ptr))) {
2214 if ((ret = krb5_dbekd_decrypt_key_data(handle->context,
2216 keyblock, keysalt)))
2220 * Coerce the enctype of the output keyblock in case we got an
2221 * inexact match on the enctype; this behavior will go away when
2222 * the key storage architecture gets redesigned for 1.3.
2225 keyblock->enctype = ktype;
2228 *kvnop = key_data->key_data_kvno;