1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
9 #include <kadm5/admin.h>
11 #include "server_internal.h"
12 #ifdef USE_PASSWORD_SERVER
17 #include <krb5/kadm5_hook_plugin.h>
20 #include <valgrind/memcheck.h>
22 #define VALGRIND_CHECK_DEFINED(LVALUE) ((void)0)
25 extern krb5_principal master_princ;
26 extern krb5_principal hist_princ;
27 extern krb5_keyblock master_keyblock;
28 extern krb5_actkvno_node *active_mkey_list;
29 extern krb5_db_entry master_db;
31 static int decrypt_key_data(krb5_context context,
32 int n_key_data, krb5_key_data *key_data,
33 krb5_keyblock **keyblocks, int *n_keys);
35 static krb5_error_code
36 kadm5_copy_principal(krb5_context context, krb5_const_principal inprinc, krb5_principal *outprinc)
38 register krb5_principal tempprinc;
39 register int i, nelems;
41 tempprinc = (krb5_principal)krb5_db_alloc(context, NULL, sizeof(krb5_principal_data));
46 VALGRIND_CHECK_DEFINED(*inprinc);
47 *tempprinc = *inprinc;
49 nelems = (int) krb5_princ_size(context, inprinc);
50 tempprinc->data = krb5_db_alloc(context, NULL, nelems * sizeof(krb5_data));
51 if (tempprinc->data == 0) {
52 krb5_db_free(context, (char *)tempprinc);
56 for (i = 0; i < nelems; i++) {
57 unsigned int len = krb5_princ_component(context, inprinc, i)->length;
58 krb5_princ_component(context, tempprinc, i)->length = len;
59 if (((krb5_princ_component(context, tempprinc, i)->data =
60 krb5_db_alloc(context, NULL, len)) == 0) && len) {
62 krb5_db_free(context, krb5_princ_component(context, tempprinc, i)->data);
63 krb5_db_free (context, tempprinc->data);
64 krb5_db_free (context, tempprinc);
68 memcpy(krb5_princ_component(context, tempprinc, i)->data,
69 krb5_princ_component(context, inprinc, i)->data, len);
70 krb5_princ_component(context, tempprinc, i)->magic = KV5M_DATA;
73 tempprinc->realm.data =
74 krb5_db_alloc(context, NULL, tempprinc->realm.length = inprinc->realm.length);
75 if (!tempprinc->realm.data && tempprinc->realm.length) {
76 for (i = 0; i < nelems; i++)
77 krb5_db_free(context, krb5_princ_component(context, tempprinc, i)->data);
78 krb5_db_free(context, tempprinc->data);
79 krb5_db_free(context, tempprinc);
82 if (tempprinc->realm.length)
83 memcpy(tempprinc->realm.data, inprinc->realm.data,
84 inprinc->realm.length);
86 *outprinc = tempprinc;
91 kadm5_free_principal(krb5_context context, krb5_principal val)
93 register krb5_int32 i;
99 i = krb5_princ_size(context, val);
101 krb5_db_free(context, krb5_princ_component(context, val, i)->data);
102 krb5_db_free(context, val->data);
105 krb5_db_free(context, val->realm.data);
106 krb5_db_free(context, val);
110 * XXX Functions that ought to be in libkrb5.a, but aren't.
112 kadm5_ret_t krb5_copy_key_data_contents(context, from, to)
113 krb5_context context;
114 krb5_key_data *from, *to;
120 idx = (from->key_data_ver == 1 ? 1 : 2);
122 for (i = 0; i < idx; i++) {
123 if ( from->key_data_length[i] ) {
124 to->key_data_contents[i] = malloc(from->key_data_length[i]);
125 if (to->key_data_contents[i] == NULL) {
126 for (i = 0; i < idx; i++) {
127 if (to->key_data_contents[i]) {
128 memset(to->key_data_contents[i], 0,
129 to->key_data_length[i]);
130 free(to->key_data_contents[i]);
135 memcpy(to->key_data_contents[i], from->key_data_contents[i],
136 from->key_data_length[i]);
142 static krb5_tl_data *dup_tl_data(krb5_tl_data *tl)
146 n = (krb5_tl_data *) malloc(sizeof(krb5_tl_data));
149 n->tl_data_contents = malloc(tl->tl_data_length);
150 if (n->tl_data_contents == NULL) {
154 memcpy(n->tl_data_contents, tl->tl_data_contents, tl->tl_data_length);
155 n->tl_data_type = tl->tl_data_type;
156 n->tl_data_length = tl->tl_data_length;
157 n->tl_data_next = NULL;
161 /* This is in lib/kdb/kdb_cpw.c, but is static */
162 static void cleanup_key_data(context, count, data)
163 krb5_context context;
165 krb5_key_data * data;
169 for (i = 0; i < count; i++)
170 for (j = 0; j < data[i].key_data_ver; j++)
171 if (data[i].key_data_length[j])
172 krb5_db_free(context, data[i].key_data_contents[j]);
173 krb5_db_free(context, data);
177 * Set *passptr to NULL if the request looks like the first part of a krb5 1.6
178 * addprinc -randkey operation. The krb5 1.6 dummy password for these requests
179 * was invalid UTF-8, which runs afoul of the arcfour string-to-key.
182 check_1_6_dummy(kadm5_principal_ent_t entry, long mask,
183 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, char **passptr)
186 char *password = *passptr;
188 /* Old-style randkey operations disallowed tickets to start. */
189 if (!(mask & KADM5_ATTRIBUTES) ||
190 !(entry->attributes & KRB5_KDB_DISALLOW_ALL_TIX))
193 /* The 1.6 dummy password was the octets 1..255. */
194 for (i = 0; (unsigned char) password[i] == i + 1; i++);
195 if (password[i] != '\0' || i != 255)
198 /* This will make the caller use a random password instead. */
203 kadm5_create_principal(void *server_handle,
204 kadm5_principal_ent_t entry, long mask,
208 kadm5_create_principal_3(server_handle, entry, mask,
212 kadm5_create_principal_3(void *server_handle,
213 kadm5_principal_ent_t entry, long mask,
214 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
218 osa_princ_ent_rec adb;
219 kadm5_policy_ent_rec polent;
220 krb5_boolean have_polent = FALSE;
222 krb5_tl_data *tl_data_orig, *tl_data_tail;
224 kadm5_server_handle_t handle = server_handle;
225 krb5_keyblock *act_mkey;
228 CHECK_HANDLE(server_handle);
230 krb5_clear_error_message(handle->context);
232 check_1_6_dummy(entry, mask, n_ks_tuple, ks_tuple, &password);
235 * Argument sanity checking, and opening up the DB
237 if(!(mask & KADM5_PRINCIPAL) || (mask & KADM5_MOD_NAME) ||
238 (mask & KADM5_MOD_TIME) || (mask & KADM5_LAST_PWD_CHANGE) ||
239 (mask & KADM5_MKVNO) || (mask & KADM5_POLICY_CLR) ||
240 (mask & KADM5_AUX_ATTRIBUTES) || (mask & KADM5_KEY_DATA) ||
241 (mask & KADM5_LAST_SUCCESS) || (mask & KADM5_LAST_FAILED) ||
242 (mask & KADM5_FAIL_AUTH_COUNT))
243 return KADM5_BAD_MASK;
244 if((mask & ~ALL_PRINC_MASK))
245 return KADM5_BAD_MASK;
249 /* Use default keysalts if caller did not provide any. */
250 if (n_ks_tuple == 0) {
251 ks_tuple = handle->params.keysalts;
252 n_ks_tuple = handle->params.num_keysalts;
256 * Check to see if the principal exists
258 ret = kdb_get_entry(handle, entry->principal, &kdb, &adb);
261 case KADM5_UNK_PRINC:
264 kdb_free_entry(handle, kdb, &adb);
270 kdb = krb5_db_alloc(handle->context, NULL, sizeof(*kdb));
273 memset(kdb, 0, sizeof(*kdb));
274 memset(&adb, 0, sizeof(osa_princ_ent_rec));
277 * If a policy was specified, load it.
278 * If we can not find the one specified return an error
280 if ((mask & KADM5_POLICY)) {
281 if ((ret = kadm5_get_policy(handle->lhandle, entry->policy,
282 &polent)) != KADM5_OK) {
284 ret = KADM5_BAD_POLICY;
291 ret = passwd_check(handle, password, have_polent ? &polent : NULL,
297 * Start populating the various DB fields, using the
298 * "defaults" for fields that were not specified by the
301 if ((ret = krb5_timeofday(handle->context, &now)))
304 kdb->magic = KRB5_KDB_MAGIC_NUMBER;
305 kdb->len = KRB5_KDB_V1_BASE_LENGTH; /* gag me with a chainsaw */
307 if ((mask & KADM5_ATTRIBUTES))
308 kdb->attributes = entry->attributes;
310 kdb->attributes = handle->params.flags;
312 if ((mask & KADM5_MAX_LIFE))
313 kdb->max_life = entry->max_life;
315 kdb->max_life = handle->params.max_life;
317 if (mask & KADM5_MAX_RLIFE)
318 kdb->max_renewable_life = entry->max_renewable_life;
320 kdb->max_renewable_life = handle->params.max_rlife;
322 if ((mask & KADM5_PRINC_EXPIRE_TIME))
323 kdb->expiration = entry->princ_expire_time;
325 kdb->expiration = handle->params.expiration;
327 kdb->pw_expiration = 0;
329 if(polent.pw_max_life)
330 kdb->pw_expiration = now + polent.pw_max_life;
332 kdb->pw_expiration = 0;
334 if ((mask & KADM5_PW_EXPIRATION))
335 kdb->pw_expiration = entry->pw_expiration;
337 kdb->last_success = 0;
338 kdb->last_failed = 0;
339 kdb->fail_auth_count = 0;
341 /* this is kind of gross, but in order to free the tl data, I need
342 to free the entire kdb entry, and that will try to free the
345 if ((ret = kadm5_copy_principal(handle->context,
346 entry->principal, &(kdb->princ))))
349 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, kdb, now)))
352 if (mask & KADM5_TL_DATA) {
353 /* splice entry->tl_data onto the front of kdb->tl_data */
354 tl_data_orig = kdb->tl_data;
355 for (tl_data_tail = entry->tl_data; tl_data_tail;
356 tl_data_tail = tl_data_tail->tl_data_next)
358 ret = krb5_dbe_update_tl_data(handle->context, kdb, tl_data_tail);
364 /* initialize the keys */
366 ret = krb5_dbe_find_act_mkey(handle->context, active_mkey_list, &act_kvno,
372 ret = krb5_dbe_cpw(handle->context, act_mkey, ks_tuple, n_ks_tuple,
373 password, (mask & KADM5_KVNO)?entry->kvno:1,
376 /* Null password means create with random key (new in 1.8). */
377 ret = krb5_dbe_crk(handle->context, &master_keyblock,
378 ks_tuple, n_ks_tuple, FALSE, kdb);
383 /* Record the master key VNO used to encrypt this entry's keys */
384 ret = krb5_dbe_update_mkvno(handle->context, kdb, act_kvno);
388 ret = k5_kadm5_hook_create(handle->context, handle->hook_handles,
389 KADM5_HOOK_STAGE_PRECOMMIT, entry, mask,
390 n_ks_tuple, ks_tuple, password);
394 /* populate the admin-server-specific fields. In the OV server,
395 this used to be in a separate database. Since there's already
396 marshalling code for the admin fields, to keep things simple,
397 I'm going to keep it, and make all the admin stuff occupy a
398 single tl_data record, */
400 adb.admin_history_kvno = INITIAL_HIST_KVNO;
402 adb.aux_attributes = KADM5_POLICY;
404 /* this does *not* need to be strdup'ed, because adb is xdr */
405 /* encoded in osa_adb_create_princ, and not ever freed */
407 adb.policy = entry->policy;
410 /* increment the policy ref count, if any */
413 polent.policy_refcnt++;
414 if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent,
420 /* In all cases key and the principal data is set, let the database provider know */
421 kdb->mask = mask | KADM5_KEY_DATA | KADM5_PRINCIPAL ;
423 /* store the new db entry */
424 ret = kdb_put_entry(handle, kdb, &adb);
429 /* decrement the policy ref count */
431 polent.policy_refcnt--;
433 * if this fails, there's nothing we can do anyway. the
434 * policy refcount wil be too high.
436 (void) kadm5_modify_policy_internal(handle->lhandle, &polent,
441 (void) k5_kadm5_hook_create(handle->context, handle->hook_handles,
442 KADM5_HOOK_STAGE_POSTCOMMIT, entry, mask,
443 n_ks_tuple, ks_tuple, password);
446 krb5_db_free_principal(handle->context, kdb);
448 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
454 kadm5_delete_principal(void *server_handle, krb5_principal principal)
457 kadm5_policy_ent_rec polent;
459 osa_princ_ent_rec adb;
460 kadm5_server_handle_t handle = server_handle;
462 CHECK_HANDLE(server_handle);
464 krb5_clear_error_message(handle->context);
466 if (principal == NULL)
469 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
471 ret = k5_kadm5_hook_remove(handle->context, handle->hook_handles,
472 KADM5_HOOK_STAGE_PRECOMMIT, principal);
474 kdb_free_entry(handle, 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);
502 (void) k5_kadm5_hook_remove(handle->context,
503 handle->hook_handles,
504 KADM5_HOOK_STAGE_POSTCOMMIT, principal);
510 kadm5_modify_principal(void *server_handle,
511 kadm5_principal_ent_t entry, long mask)
514 kadm5_policy_ent_rec npol, opol;
515 int have_npol = 0, have_opol = 0;
517 krb5_tl_data *tl_data_orig;
518 osa_princ_ent_rec adb;
519 kadm5_server_handle_t handle = server_handle;
521 CHECK_HANDLE(server_handle);
523 krb5_clear_error_message(handle->context);
525 if((mask & KADM5_PRINCIPAL) || (mask & KADM5_LAST_PWD_CHANGE) ||
526 (mask & KADM5_MOD_TIME) || (mask & KADM5_MOD_NAME) ||
527 (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) ||
528 (mask & KADM5_KEY_DATA) || (mask & KADM5_LAST_SUCCESS) ||
529 (mask & KADM5_LAST_FAILED))
530 return KADM5_BAD_MASK;
531 if((mask & ~ALL_PRINC_MASK))
532 return KADM5_BAD_MASK;
533 if((mask & KADM5_POLICY) && (mask & KADM5_POLICY_CLR))
534 return KADM5_BAD_MASK;
535 if(entry == (kadm5_principal_ent_t) NULL)
537 if (mask & KADM5_TL_DATA) {
538 tl_data_orig = entry->tl_data;
539 while (tl_data_orig) {
540 if (tl_data_orig->tl_data_type < 256)
541 return KADM5_BAD_TL_TYPE;
542 tl_data_orig = tl_data_orig->tl_data_next;
546 ret = kdb_get_entry(handle, entry->principal, &kdb, &adb);
551 * This is pretty much the same as create ...
554 if ((mask & KADM5_POLICY)) {
555 /* get the new policy */
556 ret = kadm5_get_policy(handle->lhandle, entry->policy, &npol);
560 ret = KADM5_BAD_POLICY;
562 case KADM5_UNK_POLICY:
563 case KADM5_BAD_POLICY:
564 ret = KADM5_UNK_POLICY;
571 /* if we already have a policy, get it to decrement the refcnt */
572 if(adb.aux_attributes & KADM5_POLICY) {
573 /* ... but not if the old and new are the same */
574 if(strcmp(adb.policy, entry->policy)) {
575 ret = kadm5_get_policy(handle->lhandle,
579 case KADM5_BAD_POLICY:
580 case KADM5_UNK_POLICY:
584 opol.policy_refcnt--;
590 npol.policy_refcnt++;
592 } else npol.policy_refcnt++;
594 /* set us up to use the new policy */
595 adb.aux_attributes |= KADM5_POLICY;
598 adb.policy = strdup(entry->policy);
600 /* set pw_max_life based on new policy */
601 if (npol.pw_max_life) {
602 ret = krb5_dbe_lookup_last_pwd_change(handle->context, kdb,
603 &(kdb->pw_expiration));
606 kdb->pw_expiration += npol.pw_max_life;
608 kdb->pw_expiration = 0;
612 if ((mask & KADM5_POLICY_CLR) &&
613 (adb.aux_attributes & KADM5_POLICY)) {
614 ret = kadm5_get_policy(handle->lhandle, adb.policy, &opol);
617 case KADM5_BAD_POLICY:
618 case KADM5_UNK_POLICY:
627 adb.aux_attributes &= ~KADM5_POLICY;
628 kdb->pw_expiration = 0;
629 opol.policy_refcnt--;
637 if (((mask & KADM5_POLICY) || (mask & KADM5_POLICY_CLR)) &&
640 kadm5_modify_policy_internal(handle->lhandle, &opol,
641 KADM5_REF_COUNT))) ||
644 kadm5_modify_policy_internal(handle->lhandle, &npol,
648 if ((mask & KADM5_ATTRIBUTES))
649 kdb->attributes = entry->attributes;
650 if ((mask & KADM5_MAX_LIFE))
651 kdb->max_life = entry->max_life;
652 if ((mask & KADM5_PRINC_EXPIRE_TIME))
653 kdb->expiration = entry->princ_expire_time;
654 if (mask & KADM5_PW_EXPIRATION)
655 kdb->pw_expiration = entry->pw_expiration;
656 if (mask & KADM5_MAX_RLIFE)
657 kdb->max_renewable_life = entry->max_renewable_life;
659 if((mask & KADM5_KVNO)) {
660 for (i = 0; i < kdb->n_key_data; i++)
661 kdb->key_data[i].key_data_kvno = entry->kvno;
664 if (mask & KADM5_TL_DATA) {
667 /* may have to change the version number of the API. Updates the list with the given tl_data rather than over-writting */
669 for (tl = entry->tl_data; tl;
670 tl = tl->tl_data_next)
672 ret = krb5_dbe_update_tl_data(handle->context, kdb, tl);
681 * Setting entry->fail_auth_count to 0 can be used to manually unlock
682 * an account. It is not possible to set fail_auth_count to any other
683 * value using kadmin.
685 if (mask & KADM5_FAIL_AUTH_COUNT) {
686 if (entry->fail_auth_count != 0) {
687 ret = KADM5_BAD_SERVER_PARAMS;
691 kdb->fail_auth_count = 0;
694 /* let the mask propagate to the database provider */
697 ret = k5_kadm5_hook_modify(handle->context, handle->hook_handles,
698 KADM5_HOOK_STAGE_PRECOMMIT, entry, mask);
702 ret = kdb_put_entry(handle, kdb, &adb);
704 (void) k5_kadm5_hook_modify(handle->context, handle->hook_handles,
705 KADM5_HOOK_STAGE_POSTCOMMIT, entry, mask);
710 ret2 = kadm5_free_policy_ent(handle->lhandle, &opol);
711 ret = ret ? ret : ret2;
714 ret2 = kadm5_free_policy_ent(handle->lhandle, &npol);
715 ret = ret ? ret : ret2;
717 kdb_free_entry(handle, kdb, &adb);
722 kadm5_rename_principal(void *server_handle,
723 krb5_principal source, krb5_principal target)
726 osa_princ_ent_rec adb;
728 kadm5_server_handle_t handle = server_handle;
730 krb5_data *salt = NULL;
732 CHECK_HANDLE(server_handle);
734 krb5_clear_error_message(handle->context);
736 if (source == NULL || target == NULL)
739 if ((ret = kdb_get_entry(handle, target, &kdb, &adb)) == 0) {
740 kdb_free_entry(handle, kdb, &adb);
744 if ((ret = kdb_get_entry(handle, source, &kdb, &adb)))
747 /* Transform salts as necessary. */
748 for (i = 0; i < kdb->n_key_data; i++) {
749 ret = krb5_dbe_compute_salt(handle->context, &kdb->key_data[i],
750 kdb->princ, &stype, &salt);
751 if (ret == KRB5_KDB_BAD_SALTTYPE)
752 ret = KADM5_NO_RENAME_SALT;
755 kdb->key_data[i].key_data_type[1] = KRB5_KDB_SALTTYPE_SPECIAL;
756 free(kdb->key_data[i].key_data_contents[1]);
757 kdb->key_data[i].key_data_contents[1] = (krb5_octet *)salt->data;
758 kdb->key_data[i].key_data_length[1] = salt->length;
759 kdb->key_data[i].key_data_ver = 2;
764 kadm5_free_principal(handle->context, kdb->princ);
765 ret = kadm5_copy_principal(handle->context, target, &kdb->princ);
767 kdb->princ = NULL; /* so freeing the dbe doesn't lose */
771 if ((ret = kdb_put_entry(handle, kdb, &adb)))
774 ret = kdb_delete_entry(handle, source);
777 krb5_free_data(handle->context, salt);
778 kdb_free_entry(handle, kdb, &adb);
783 kadm5_get_principal(void *server_handle, krb5_principal principal,
784 kadm5_principal_ent_t entry,
788 osa_princ_ent_rec adb;
789 krb5_error_code ret = 0;
792 kadm5_server_handle_t handle = server_handle;
794 CHECK_HANDLE(server_handle);
796 krb5_clear_error_message(handle->context);
799 * In version 1, all the defined fields are always returned.
800 * entry is a pointer to a kadm5_principal_ent_t_v1 that should be
801 * filled with allocated memory.
805 memset(entry, 0, sizeof(*entry));
807 if (principal == NULL)
810 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
813 if ((mask & KADM5_POLICY) &&
814 adb.policy && (adb.aux_attributes & KADM5_POLICY)) {
815 if ((entry->policy = strdup(adb.policy)) == NULL) {
821 if (mask & KADM5_AUX_ATTRIBUTES)
822 entry->aux_attributes = adb.aux_attributes;
824 if ((mask & KADM5_PRINCIPAL) &&
825 (ret = krb5_copy_principal(handle->context, kdb->princ,
826 &entry->principal))) {
830 if (mask & KADM5_PRINC_EXPIRE_TIME)
831 entry->princ_expire_time = kdb->expiration;
833 if ((mask & KADM5_LAST_PWD_CHANGE) &&
834 (ret = krb5_dbe_lookup_last_pwd_change(handle->context, kdb,
835 &(entry->last_pwd_change)))) {
839 if (mask & KADM5_PW_EXPIRATION)
840 entry->pw_expiration = kdb->pw_expiration;
841 if (mask & KADM5_MAX_LIFE)
842 entry->max_life = kdb->max_life;
844 /* this is a little non-sensical because the function returns two */
845 /* values that must be checked separately against the mask */
846 if ((mask & KADM5_MOD_NAME) || (mask & KADM5_MOD_TIME)) {
847 ret = krb5_dbe_lookup_mod_princ_data(handle->context, kdb,
854 if (! (mask & KADM5_MOD_TIME))
856 if (! (mask & KADM5_MOD_NAME)) {
857 krb5_free_principal(handle->context, entry->mod_name);
858 entry->mod_name = NULL;
862 if (mask & KADM5_ATTRIBUTES)
863 entry->attributes = kdb->attributes;
865 if (mask & KADM5_KVNO)
866 for (entry->kvno = 0, i=0; i<kdb->n_key_data; i++)
867 if ((krb5_kvno) kdb->key_data[i].key_data_kvno > entry->kvno)
868 entry->kvno = kdb->key_data[i].key_data_kvno;
870 if (mask & KADM5_MKVNO) {
871 ret = krb5_dbe_get_mkvno(handle->context, kdb, &entry->mkvno);
876 if (mask & KADM5_MAX_RLIFE)
877 entry->max_renewable_life = kdb->max_renewable_life;
878 if (mask & KADM5_LAST_SUCCESS)
879 entry->last_success = kdb->last_success;
880 if (mask & KADM5_LAST_FAILED)
881 entry->last_failed = kdb->last_failed;
882 if (mask & KADM5_FAIL_AUTH_COUNT)
883 entry->fail_auth_count = kdb->fail_auth_count;
884 if (mask & KADM5_TL_DATA) {
885 krb5_tl_data *tl, *tl2;
887 entry->tl_data = NULL;
891 if (tl->tl_data_type > 255) {
892 if ((tl2 = dup_tl_data(tl)) == NULL) {
896 tl2->tl_data_next = entry->tl_data;
897 entry->tl_data = tl2;
901 tl = tl->tl_data_next;
904 if (mask & KADM5_KEY_DATA) {
905 entry->n_key_data = kdb->n_key_data;
906 if(entry->n_key_data) {
907 entry->key_data = malloc(entry->n_key_data*sizeof(krb5_key_data));
908 if (entry->key_data == NULL) {
913 entry->key_data = NULL;
915 for (i = 0; i < entry->n_key_data; i++)
916 ret = krb5_copy_key_data_contents(handle->context,
918 &entry->key_data[i]);
926 if (ret && entry->principal) {
927 krb5_free_principal(handle->context, entry->principal);
928 entry->principal = NULL;
930 kdb_free_entry(handle, kdb, &adb);
936 * Function: check_pw_reuse
938 * Purpose: Check if a key appears in a list of keys, in order to
939 * enforce password history.
943 * context (r) the krb5 context
944 * hist_keyblock (r) the key that hist_key_data is
946 * n_new_key_data (r) length of new_key_data
947 * new_key_data (r) keys to check against
948 * pw_hist_data, encrypted in hist_keyblock
949 * n_pw_hist_data (r) length of pw_hist_data
950 * pw_hist_data (r) passwords to check new_key_data against
953 * For each new_key in new_key_data:
954 * decrypt new_key with the master_keyblock
955 * for each password in pw_hist_data:
956 * for each hist_key in password:
957 * decrypt hist_key with hist_keyblock
958 * compare the new_key and hist_key
960 * Returns krb5 errors, KADM5_PASS_RESUSE if a key in
961 * new_key_data is the same as a key in pw_hist_data, or 0.
964 check_pw_reuse(krb5_context context,
965 krb5_keyblock *hist_keyblocks,
966 int n_new_key_data, krb5_key_data *new_key_data,
967 unsigned int n_pw_hist_data, osa_pw_hist_ent *pw_hist_data)
969 unsigned int x, y, z;
970 krb5_keyblock newkey, histkey, *kb;
971 krb5_key_data *key_data;
974 assert (n_new_key_data >= 0);
975 for (x = 0; x < (unsigned) n_new_key_data; x++) {
976 /* Check only entries with the most recent kvno. */
977 if (new_key_data[x].key_data_kvno != new_key_data[0].key_data_kvno)
979 ret = krb5_dbe_decrypt_key_data(context, NULL, &(new_key_data[x]),
983 for (y = 0; y < n_pw_hist_data; y++) {
984 for (z = 0; z < (unsigned int) pw_hist_data[y].n_key_data; z++) {
985 for (kb = hist_keyblocks; kb->enctype != 0; kb++) {
986 key_data = &pw_hist_data[y].key_data[z];
987 ret = krb5_dbe_decrypt_key_data(context, kb, key_data,
991 if (newkey.length == histkey.length &&
992 newkey.enctype == histkey.enctype &&
993 memcmp(newkey.contents, histkey.contents,
994 histkey.length) == 0) {
995 krb5_free_keyblock_contents(context, &histkey);
996 krb5_free_keyblock_contents(context, &newkey);
997 return KADM5_PASS_REUSE;
999 krb5_free_keyblock_contents(context, &histkey);
1003 krb5_free_keyblock_contents(context, &newkey);
1010 * Function: create_history_entry
1012 * Purpose: Creates a password history entry from an array of
1017 * context (r) krb5_context to use
1018 * mkey (r) master keyblock to decrypt key data with
1019 * hist_key (r) history keyblock to encrypt key data with
1020 * n_key_data (r) number of elements in key_data
1021 * key_data (r) keys to add to the history entry
1022 * hist (w) history entry to fill in
1026 * hist->key_data is allocated to store n_key_data key_datas. Each
1027 * element of key_data is decrypted with master_keyblock, re-encrypted
1028 * in hist_key, and added to hist->key_data. hist->n_key_data is
1029 * set to n_key_data.
1032 int create_history_entry(krb5_context context,
1033 krb5_keyblock *hist_key, int n_key_data,
1034 krb5_key_data *key_data, osa_pw_hist_ent *hist)
1040 hist->key_data = (krb5_key_data*)malloc(n_key_data*sizeof(krb5_key_data));
1041 if (hist->key_data == NULL)
1043 memset(hist->key_data, 0, n_key_data*sizeof(krb5_key_data));
1045 for (i = 0; i < n_key_data; i++) {
1046 ret = krb5_dbe_decrypt_key_data(context, NULL, &key_data[i], &key,
1051 ret = krb5_dbe_encrypt_key_data(context, hist_key, &key, &salt,
1052 key_data[i].key_data_kvno,
1053 &hist->key_data[i]);
1057 krb5_free_keyblock_contents(context, &key);
1058 /* krb5_free_keysalt(context, &salt); */
1061 hist->n_key_data = n_key_data;
1066 void free_history_entry(krb5_context context, osa_pw_hist_ent *hist)
1070 for (i = 0; i < hist->n_key_data; i++)
1071 krb5_free_key_data_contents(context, &hist->key_data[i]);
1072 free(hist->key_data);
1076 * Function: add_to_history
1078 * Purpose: Adds a password to a principal's password history.
1082 * context (r) krb5_context to use
1083 * hist_kvno (r) kvno of current history key
1084 * adb (r/w) admin principal entry to add keys to
1085 * pol (r) adb's policy
1086 * pw (r) keys for the password to add to adb's key history
1090 * add_to_history adds a single password to adb's password history.
1091 * pw contains n_key_data keys in its key_data, in storage should be
1092 * allocated but not freed by the caller (XXX blech!).
1094 * This function maintains adb->old_keys as a circular queue. It
1095 * starts empty, and grows each time this function is called until it
1096 * is pol->pw_history_num items long. adb->old_key_len holds the
1097 * number of allocated entries in the array, and must therefore be [0,
1098 * pol->pw_history_num). adb->old_key_next is the index into the
1099 * array where the next element should be written, and must be [0,
1100 * adb->old_key_len).
1102 static kadm5_ret_t add_to_history(krb5_context context,
1103 krb5_kvno hist_kvno,
1104 osa_princ_ent_t adb,
1105 kadm5_policy_ent_t pol,
1106 osa_pw_hist_ent *pw)
1108 osa_pw_hist_ent *histp;
1110 unsigned int i, knext, nkeys;
1112 nhist = pol->pw_history_num;
1113 /* A history of 1 means just check the current password */
1117 if (adb->admin_history_kvno != hist_kvno) {
1118 /* The history key has changed since the last password change, so we
1119 * have to reset the password history. */
1120 free(adb->old_keys);
1121 adb->old_keys = NULL;
1122 adb->old_key_len = 0;
1123 adb->old_key_next = 0;
1124 adb->admin_history_kvno = hist_kvno;
1127 nkeys = adb->old_key_len;
1128 knext = adb->old_key_next;
1129 /* resize the adb->old_keys array if necessary */
1130 if (nkeys + 1 < nhist) {
1131 if (adb->old_keys == NULL) {
1132 adb->old_keys = (osa_pw_hist_ent *)
1133 malloc((nkeys + 1) * sizeof (osa_pw_hist_ent));
1135 adb->old_keys = (osa_pw_hist_ent *)
1136 realloc(adb->old_keys,
1137 (nkeys + 1) * sizeof (osa_pw_hist_ent));
1139 if (adb->old_keys == NULL)
1142 memset(&adb->old_keys[nkeys], 0, sizeof(osa_pw_hist_ent));
1143 nkeys = ++adb->old_key_len;
1145 * To avoid losing old keys, shift forward each entry after
1148 for (i = nkeys - 1; i > knext; i--) {
1149 adb->old_keys[i] = adb->old_keys[i - 1];
1151 memset(&adb->old_keys[knext], 0, sizeof(osa_pw_hist_ent));
1152 } else if (nkeys + 1 > nhist) {
1154 * The policy must have changed! Shrink the array.
1155 * Can't simply realloc() down, since it might be wrapped.
1156 * To understand the arithmetic below, note that we are
1157 * copying into new positions 0 .. N-1 from old positions
1158 * old_key_next-N .. old_key_next-1, modulo old_key_len,
1159 * where N = pw_history_num - 1 is the length of the
1160 * shortened list. Matt Crawford, FNAL
1163 * M = adb->old_key_len, N = pol->pw_history_num - 1
1165 * tmp[0] .. tmp[N-1] = old[(knext-N)%M] .. old[(knext-1)%M]
1170 tmp = (osa_pw_hist_ent *)
1171 malloc((nhist - 1) * sizeof (osa_pw_hist_ent));
1174 for (i = 0; i < nhist - 1; i++) {
1176 * Add nkeys once before taking remainder to avoid
1179 j = (i + nkeys + knext - (nhist - 1)) % nkeys;
1180 tmp[i] = adb->old_keys[j];
1182 /* Now free the ones we don't keep (the oldest ones) */
1183 for (i = 0; i < nkeys - (nhist - 1); i++) {
1184 j = (i + nkeys + knext) % nkeys;
1185 histp = &adb->old_keys[j];
1186 for (j = 0; j < histp->n_key_data; j++) {
1187 krb5_free_key_data_contents(context, &histp->key_data[j]);
1189 free(histp->key_data);
1191 free(adb->old_keys);
1192 adb->old_keys = tmp;
1193 nkeys = adb->old_key_len = nhist - 1;
1194 knext = adb->old_key_next = 0;
1198 * If nhist decreased since the last password change, and nkeys+1
1199 * is less than the previous nhist, it is possible for knext to
1200 * index into unallocated space. This condition would not be
1201 * caught by the resizing code above.
1203 if (knext + 1 > nkeys)
1204 knext = adb->old_key_next = 0;
1205 /* free the old pw history entry if it contains data */
1206 histp = &adb->old_keys[knext];
1207 for (i = 0; i < (unsigned int) histp->n_key_data; i++)
1208 krb5_free_key_data_contents(context, &histp->key_data[i]);
1209 free(histp->key_data);
1211 /* store the new entry */
1212 adb->old_keys[knext] = *pw;
1214 /* update the next pointer */
1215 if (++adb->old_key_next == nhist - 1)
1216 adb->old_key_next = 0;
1221 /* FIXME: don't use global variable for this */
1222 krb5_boolean use_password_server = 0;
1224 #ifdef USE_PASSWORD_SERVER
1226 kadm5_use_password_server (void)
1228 return use_password_server;
1233 kadm5_set_use_password_server (void)
1235 use_password_server = 1;
1238 #ifdef USE_PASSWORD_SERVER
1241 * kadm5_launch_task () runs a program (task_path) to synchronize the
1242 * Apple password server with the Kerberos database. Password server
1243 * programs can receive arguments on the command line (task_argv)
1244 * and a block of data via stdin (data_buffer).
1246 * Because a failure to communicate with the tool results in the
1247 * password server falling out of sync with the database,
1248 * kadm5_launch_task() always fails if it can't talk to the tool.
1252 kadm5_launch_task (krb5_context context,
1253 const char *task_path, char * const task_argv[],
1259 ret = pipe (data_pipe);
1264 pid_t pid = fork ();
1267 close (data_pipe[0]);
1268 close (data_pipe[1]);
1269 } else if (pid == 0) {
1272 if (dup2 (data_pipe[0], STDIN_FILENO) == -1)
1275 close (data_pipe[0]);
1276 close (data_pipe[1]);
1278 execv (task_path, task_argv);
1280 _exit (1); /* Fail if execv fails */
1287 close (data_pipe[0]);
1289 /* Write out the buffer to the child, add \n */
1291 if (krb5_net_write (context, data_pipe[1], buffer, strlen (buffer)) < 0
1292 || krb5_net_write (context, data_pipe[1], "\n", 1) < 0)
1294 /* kill the child to make sure waitpid() won't hang later */
1296 kill (pid, SIGKILL);
1299 close (data_pipe[1]);
1301 waitpid (pid, &status, 0);
1304 if (WIFEXITED (status)) {
1305 /* child read password and exited. Check the return value. */
1306 if ((WEXITSTATUS (status) != 0) && (WEXITSTATUS (status) != 252)) {
1307 ret = KRB5KDC_ERR_POLICY; /* password change rejected */
1310 /* child read password but crashed or was killed */
1311 ret = KRB5KRB_ERR_GENERIC; /* FIXME: better error */
1323 kadm5_chpass_principal(void *server_handle,
1324 krb5_principal principal, char *password)
1327 kadm5_chpass_principal_3(server_handle, principal, FALSE,
1332 kadm5_chpass_principal_3(void *server_handle,
1333 krb5_principal principal, krb5_boolean keepold,
1334 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1338 kadm5_policy_ent_rec pol;
1339 osa_princ_ent_rec adb;
1341 int ret, ret2, last_pwd, hist_added;
1343 kadm5_server_handle_t handle = server_handle;
1344 osa_pw_hist_ent hist;
1345 krb5_keyblock *act_mkey, *hist_keyblocks = NULL;
1346 krb5_kvno act_kvno, hist_kvno;
1348 CHECK_HANDLE(server_handle);
1350 krb5_clear_error_message(handle->context);
1353 memset(&hist, 0, sizeof(hist));
1355 if (principal == NULL || password == NULL)
1357 if ((krb5_principal_compare(handle->context,
1358 principal, hist_princ)) == TRUE)
1359 return KADM5_PROTECT_PRINCIPAL;
1361 /* Use default keysalts if caller did not provide any. */
1362 if (n_ks_tuple == 0) {
1363 ks_tuple = handle->params.keysalts;
1364 n_ks_tuple = handle->params.num_keysalts;
1367 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1370 if ((adb.aux_attributes & KADM5_POLICY)) {
1371 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &pol)))
1375 /* Create a password history entry before we change kdb's key_data. */
1376 ret = kdb_get_hist_key(handle, &hist_keyblocks, &hist_kvno);
1379 ret = create_history_entry(handle->context, &hist_keyblocks[0],
1380 kdb->n_key_data, kdb->key_data, &hist);
1385 if ((ret = passwd_check(handle, password, have_pol ? &pol : NULL,
1389 ret = krb5_dbe_find_act_mkey(handle->context, active_mkey_list, &act_kvno,
1394 ret = krb5_dbe_cpw(handle->context, act_mkey, ks_tuple, n_ks_tuple,
1395 password, 0 /* increment kvno */,
1400 ret = krb5_dbe_update_mkvno(handle->context, kdb, act_kvno);
1404 kdb->attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1406 ret = krb5_timeofday(handle->context, &now);
1410 if ((adb.aux_attributes & KADM5_POLICY)) {
1411 /* the policy was loaded before */
1413 ret = krb5_dbe_lookup_last_pwd_change(handle->context, kdb, &last_pwd);
1419 * The spec says this check is overridden if the caller has
1420 * modify privilege. The admin server therefore makes this
1421 * check itself (in chpass_principal_wrapper, misc.c). A
1422 * local caller implicitly has all authorization bits.
1424 if ((now - last_pwd) < pol.pw_min_life &&
1425 !(kdb->attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1426 ret = KADM5_PASS_TOOSOON;
1431 ret = check_pw_reuse(handle->context, hist_keyblocks,
1432 kdb->n_key_data, kdb->key_data,
1437 if (pol.pw_history_num > 1) {
1438 /* If hist_kvno has changed since the last password change, we
1439 * can't check the history. */
1440 if (adb.admin_history_kvno == hist_kvno) {
1441 ret = check_pw_reuse(handle->context, hist_keyblocks,
1442 kdb->n_key_data, kdb->key_data,
1443 adb.old_key_len, adb.old_keys);
1448 ret = add_to_history(handle->context, hist_kvno, &adb, &pol,
1455 if (pol.pw_max_life)
1456 kdb->pw_expiration = now + pol.pw_max_life;
1458 kdb->pw_expiration = 0;
1460 kdb->pw_expiration = 0;
1463 #ifdef USE_PASSWORD_SERVER
1464 if (kadm5_use_password_server () &&
1465 (krb5_princ_size (handle->context, principal) == 1)) {
1466 krb5_data *princ = krb5_princ_component (handle->context, principal, 0);
1467 const char *path = "/usr/sbin/mkpassdb";
1468 char *argv[] = { "mkpassdb", "-setpassword", NULL, NULL };
1469 char *pstring = NULL;
1472 pstring = malloc ((princ->length + 1) * sizeof (char));
1473 if (pstring == NULL) { ret = ENOMEM; }
1477 memcpy (pstring, princ->data, princ->length);
1478 pstring [princ->length] = '\0';
1481 ret = kadm5_launch_task (handle->context, path, argv, password);
1484 if (pstring != NULL)
1492 ret = krb5_dbe_update_last_pwd_change(handle->context, kdb, now);
1496 /* unlock principal on this KDC */
1497 kdb->fail_auth_count = 0;
1499 /* key data and attributes changed, let the database provider know */
1500 kdb->mask = KADM5_KEY_DATA | KADM5_ATTRIBUTES |
1501 KADM5_FAIL_AUTH_COUNT;
1502 /* | KADM5_CPW_FUNCTION */
1504 ret = k5_kadm5_hook_chpass(handle->context, handle->hook_handles,
1505 KADM5_HOOK_STAGE_PRECOMMIT, principal, keepold,
1506 n_ks_tuple, ks_tuple, password);
1510 if ((ret = kdb_put_entry(handle, kdb, &adb)))
1513 (void) k5_kadm5_hook_chpass(handle->context, handle->hook_handles,
1514 KADM5_HOOK_STAGE_POSTCOMMIT, principal,
1515 keepold, n_ks_tuple, ks_tuple, password);
1518 if (!hist_added && hist.key_data)
1519 free_history_entry(handle->context, &hist);
1520 kdb_free_entry(handle, kdb, &adb);
1521 kdb_free_keyblocks(handle, hist_keyblocks);
1523 if (have_pol && (ret2 = kadm5_free_policy_ent(handle->lhandle, &pol))
1531 kadm5_randkey_principal(void *server_handle,
1532 krb5_principal principal,
1533 krb5_keyblock **keyblocks,
1537 kadm5_randkey_principal_3(server_handle, principal,
1542 kadm5_randkey_principal_3(void *server_handle,
1543 krb5_principal principal,
1544 krb5_boolean keepold,
1545 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1546 krb5_keyblock **keyblocks,
1550 osa_princ_ent_rec adb;
1552 kadm5_policy_ent_rec pol;
1553 int ret, last_pwd, have_pol = 0;
1554 kadm5_server_handle_t handle = server_handle;
1555 krb5_keyblock *act_mkey;
1560 CHECK_HANDLE(server_handle);
1562 /* Use default keysalts if caller did not provide any. */
1563 if (n_ks_tuple == 0) {
1564 ks_tuple = handle->params.keysalts;
1565 n_ks_tuple = handle->params.num_keysalts;
1568 krb5_clear_error_message(handle->context);
1570 if (principal == NULL)
1572 if (krb5_principal_compare(handle->context, principal, hist_princ)) {
1573 /* If changing the history entry, the new entry must have exactly one
1576 return KADM5_PROTECT_PRINCIPAL;
1580 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1583 ret = krb5_dbe_find_act_mkey(handle->context, active_mkey_list, NULL,
1588 ret = krb5_dbe_crk(handle->context, act_mkey, ks_tuple, n_ks_tuple,
1593 kdb->attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1595 ret = krb5_timeofday(handle->context, &now);
1599 if ((adb.aux_attributes & KADM5_POLICY)) {
1600 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1605 ret = krb5_dbe_lookup_last_pwd_change(handle->context, kdb, &last_pwd);
1611 * The spec says this check is overridden if the caller has
1612 * modify privilege. The admin server therefore makes this
1613 * check itself (in chpass_principal_wrapper, misc.c). A
1614 * local caller implicitly has all authorization bits.
1616 if((now - last_pwd) < pol.pw_min_life &&
1617 !(kdb->attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1618 ret = KADM5_PASS_TOOSOON;
1623 if (pol.pw_max_life)
1624 kdb->pw_expiration = now + pol.pw_max_life;
1626 kdb->pw_expiration = 0;
1628 kdb->pw_expiration = 0;
1631 ret = krb5_dbe_update_last_pwd_change(handle->context, kdb, now);
1635 /* unlock principal on this KDC */
1636 kdb->fail_auth_count = 0;
1639 ret = decrypt_key_data(handle->context,
1640 kdb->n_key_data, kdb->key_data,
1646 /* key data changed, let the database provider know */
1647 kdb->mask = KADM5_KEY_DATA | KADM5_FAIL_AUTH_COUNT;
1648 /* | KADM5_RANDKEY_USED */;
1650 ret = k5_kadm5_hook_chpass(handle->context, handle->hook_handles,
1651 KADM5_HOOK_STAGE_PRECOMMIT, principal, keepold,
1652 n_ks_tuple, ks_tuple, NULL);
1655 if ((ret = kdb_put_entry(handle, kdb, &adb)))
1658 (void) k5_kadm5_hook_chpass(handle->context, handle->hook_handles,
1659 KADM5_HOOK_STAGE_POSTCOMMIT, principal,
1660 keepold, n_ks_tuple, ks_tuple, NULL);
1663 kdb_free_entry(handle, kdb, &adb);
1665 kadm5_free_policy_ent(handle->lhandle, &pol);
1671 * kadm5_setv4key_principal:
1673 * Set only ONE key of the principal, removing all others. This key
1674 * must have the DES_CBC_CRC enctype and is entered as having the
1675 * krb4 salttype. This is to enable things like kadmind4 to work.
1678 kadm5_setv4key_principal(void *server_handle,
1679 krb5_principal principal,
1680 krb5_keyblock *keyblock)
1683 osa_princ_ent_rec adb;
1685 kadm5_policy_ent_rec pol;
1686 krb5_keysalt keysalt;
1687 int i, k, kvno, ret, have_pol = 0;
1691 kadm5_server_handle_t handle = server_handle;
1692 krb5_key_data tmp_key_data;
1693 krb5_keyblock *act_mkey;
1695 memset( &tmp_key_data, 0, sizeof(tmp_key_data));
1697 CHECK_HANDLE(server_handle);
1699 krb5_clear_error_message(handle->context);
1701 if (principal == NULL || keyblock == NULL)
1703 if (hist_princ && /* this will be NULL when initializing the databse */
1704 ((krb5_principal_compare(handle->context,
1705 principal, hist_princ)) == TRUE))
1706 return KADM5_PROTECT_PRINCIPAL;
1708 if (keyblock->enctype != ENCTYPE_DES_CBC_CRC)
1709 return KADM5_SETV4KEY_INVAL_ENCTYPE;
1711 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1714 for (kvno = 0, i=0; i<kdb->n_key_data; i++)
1715 if (kdb->key_data[i].key_data_kvno > kvno)
1716 kvno = kdb->key_data[i].key_data_kvno;
1718 if (kdb->key_data != NULL)
1719 cleanup_key_data(handle->context, kdb->n_key_data, kdb->key_data);
1721 kdb->key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, sizeof(krb5_key_data));
1722 if (kdb->key_data == NULL)
1724 memset(kdb->key_data, 0, sizeof(krb5_key_data));
1725 kdb->n_key_data = 1;
1726 keysalt.type = KRB5_KDB_SALTTYPE_V4;
1727 /* XXX data.magic? */
1728 keysalt.data.length = 0;
1729 keysalt.data.data = NULL;
1731 ret = krb5_dbe_find_act_mkey(handle->context, active_mkey_list, NULL,
1736 /* use tmp_key_data as temporary location and reallocate later */
1737 ret = krb5_dbe_encrypt_key_data(handle->context, act_mkey, keyblock,
1738 &keysalt, kvno + 1, &tmp_key_data);
1743 for (k = 0; k < tmp_key_data.key_data_ver; k++) {
1744 kdb->key_data->key_data_type[k] = tmp_key_data.key_data_type[k];
1745 kdb->key_data->key_data_length[k] = tmp_key_data.key_data_length[k];
1746 if (tmp_key_data.key_data_contents[k]) {
1747 kdb->key_data->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]);
1748 if (kdb->key_data->key_data_contents[k] == NULL) {
1749 cleanup_key_data(handle->context, kdb->n_key_data, kdb->key_data);
1750 kdb->key_data = NULL;
1751 kdb->n_key_data = 0;
1755 memcpy (kdb->key_data->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
1757 memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
1758 free (tmp_key_data.key_data_contents[k]);
1759 tmp_key_data.key_data_contents[k] = NULL;
1765 kdb->attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1767 ret = krb5_timeofday(handle->context, &now);
1771 if ((adb.aux_attributes & KADM5_POLICY)) {
1772 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1779 * The spec says this check is overridden if the caller has
1780 * modify privilege. The admin server therefore makes this
1781 * check itself (in chpass_principal_wrapper, misc.c). A
1782 * local caller implicitly has all authorization bits.
1784 if (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1787 if((now - last_pwd) < pol.pw_min_life &&
1788 !(kdb->attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1789 ret = KADM5_PASS_TOOSOON;
1794 if (pol.pw_max_life)
1795 kdb->pw_expiration = now + pol.pw_max_life;
1797 kdb->pw_expiration = 0;
1799 kdb->pw_expiration = 0;
1802 ret = krb5_dbe_update_last_pwd_change(handle->context, kdb, now);
1806 /* unlock principal on this KDC */
1807 kdb->fail_auth_count = 0;
1809 if ((ret = kdb_put_entry(handle, kdb, &adb)))
1814 for (i = 0; i < tmp_key_data.key_data_ver; i++) {
1815 if (tmp_key_data.key_data_contents[i]) {
1816 memset (tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]);
1817 free (tmp_key_data.key_data_contents[i]);
1821 kdb_free_entry(handle, kdb, &adb);
1823 kadm5_free_policy_ent(handle->lhandle, &pol);
1829 kadm5_setkey_principal(void *server_handle,
1830 krb5_principal principal,
1831 krb5_keyblock *keyblocks,
1835 kadm5_setkey_principal_3(server_handle, principal,
1841 kadm5_setkey_principal_3(void *server_handle,
1842 krb5_principal principal,
1843 krb5_boolean keepold,
1844 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1845 krb5_keyblock *keyblocks,
1849 osa_princ_ent_rec adb;
1851 kadm5_policy_ent_rec pol;
1852 krb5_key_data *old_key_data;
1854 int i, j, k, kvno, ret, have_pol = 0;
1858 kadm5_server_handle_t handle = server_handle;
1859 krb5_boolean similar;
1860 krb5_keysalt keysalt;
1861 krb5_key_data tmp_key_data;
1862 krb5_key_data *tptr;
1863 krb5_keyblock *act_mkey;
1865 CHECK_HANDLE(server_handle);
1867 krb5_clear_error_message(handle->context);
1869 if (principal == NULL || keyblocks == NULL)
1871 if (hist_princ && /* this will be NULL when initializing the databse */
1872 ((krb5_principal_compare(handle->context,
1873 principal, hist_princ)) == TRUE))
1874 return KADM5_PROTECT_PRINCIPAL;
1876 for (i = 0; i < n_keys; i++) {
1877 for (j = i+1; j < n_keys; j++) {
1878 if ((ret = krb5_c_enctype_compare(handle->context,
1879 keyblocks[i].enctype,
1880 keyblocks[j].enctype,
1885 if (ks_tuple[i].ks_salttype == ks_tuple[j].ks_salttype)
1886 return KADM5_SETKEY_DUP_ENCTYPES;
1888 return KADM5_SETKEY_DUP_ENCTYPES;
1893 if (n_ks_tuple && n_ks_tuple != n_keys)
1894 return KADM5_SETKEY3_ETYPE_MISMATCH;
1896 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1899 for (kvno = 0, i=0; i<kdb->n_key_data; i++)
1900 if (kdb->key_data[i].key_data_kvno > kvno)
1901 kvno = kdb->key_data[i].key_data_kvno;
1904 old_key_data = kdb->key_data;
1905 n_old_keys = kdb->n_key_data;
1907 if (kdb->key_data != NULL)
1908 cleanup_key_data(handle->context, kdb->n_key_data, kdb->key_data);
1910 old_key_data = NULL;
1913 kdb->key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, (n_keys+n_old_keys)
1914 *sizeof(krb5_key_data));
1915 if (kdb->key_data == NULL) {
1920 memset(kdb->key_data, 0, (n_keys+n_old_keys)*sizeof(krb5_key_data));
1921 kdb->n_key_data = 0;
1923 for (i = 0; i < n_keys; i++) {
1925 keysalt.type = ks_tuple[i].ks_salttype;
1926 keysalt.data.length = 0;
1927 keysalt.data.data = NULL;
1928 if (ks_tuple[i].ks_enctype != keyblocks[i].enctype) {
1929 ret = KADM5_SETKEY3_ETYPE_MISMATCH;
1933 memset (&tmp_key_data, 0, sizeof(tmp_key_data));
1935 ret = krb5_dbe_find_act_mkey(handle->context, active_mkey_list, NULL,
1940 ret = krb5_dbe_encrypt_key_data(handle->context, act_mkey,
1942 n_ks_tuple ? &keysalt : NULL, kvno + 1,
1947 tptr = &kdb->key_data[i];
1948 tptr->key_data_ver = tmp_key_data.key_data_ver;
1949 tptr->key_data_kvno = tmp_key_data.key_data_kvno;
1950 for (k = 0; k < tmp_key_data.key_data_ver; k++) {
1951 tptr->key_data_type[k] = tmp_key_data.key_data_type[k];
1952 tptr->key_data_length[k] = tmp_key_data.key_data_length[k];
1953 if (tmp_key_data.key_data_contents[k]) {
1954 tptr->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]);
1955 if (tptr->key_data_contents[k] == NULL) {
1957 for (i1 = k; i1 < tmp_key_data.key_data_ver; i1++) {
1958 if (tmp_key_data.key_data_contents[i1]) {
1959 memset (tmp_key_data.key_data_contents[i1], 0, tmp_key_data.key_data_length[i1]);
1960 free (tmp_key_data.key_data_contents[i1]);
1967 memcpy (tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
1969 memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
1970 free (tmp_key_data.key_data_contents[k]);
1971 tmp_key_data.key_data_contents[k] = NULL;
1977 /* copy old key data if necessary */
1978 for (i = 0; i < n_old_keys; i++) {
1979 kdb->key_data[i+n_keys] = old_key_data[i];
1980 memset(&old_key_data[i], 0, sizeof (krb5_key_data));
1985 krb5_db_free(handle->context, old_key_data);
1987 /* assert(kdb->n_key_data == n_keys + n_old_keys) */
1988 kdb->attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1990 if ((ret = krb5_timeofday(handle->context, &now)))
1993 if ((adb.aux_attributes & KADM5_POLICY)) {
1994 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
2001 * The spec says this check is overridden if the caller has
2002 * modify privilege. The admin server therefore makes this
2003 * check itself (in chpass_principal_wrapper, misc.c). A
2004 * local caller implicitly has all authorization bits.
2006 if (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
2009 if((now - last_pwd) < pol.pw_min_life &&
2010 !(kdb->attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
2011 ret = KADM5_PASS_TOOSOON;
2016 if (pol.pw_max_life)
2017 kdb->pw_expiration = now + pol.pw_max_life;
2019 kdb->pw_expiration = 0;
2021 kdb->pw_expiration = 0;
2024 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, kdb, now)))
2027 /* unlock principal on this KDC */
2028 kdb->fail_auth_count = 0;
2030 if ((ret = kdb_put_entry(handle, kdb, &adb)))
2035 kdb_free_entry(handle, kdb, &adb);
2037 kadm5_free_policy_ent(handle->lhandle, &pol);
2043 * Return the list of keys like kadm5_randkey_principal,
2044 * but don't modify the principal.
2047 kadm5_get_principal_keys(void *server_handle /* IN */,
2048 krb5_principal principal /* IN */,
2049 krb5_keyblock **keyblocks /* OUT */,
2050 int *n_keys /* OUT */)
2053 osa_princ_ent_rec adb;
2055 kadm5_server_handle_t handle = server_handle;
2060 CHECK_HANDLE(server_handle);
2062 if (principal == NULL)
2065 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
2069 ret = decrypt_key_data(handle->context,
2070 kdb->n_key_data, kdb->key_data,
2078 kdb_free_entry(handle, kdb, &adb);
2085 * Allocate an array of n_key_data krb5_keyblocks, fill in each
2086 * element with the results of decrypting the nth key in key_data,
2087 * and if n_keys is not NULL fill it in with the
2088 * number of keys decrypted.
2090 static int decrypt_key_data(krb5_context context,
2091 int n_key_data, krb5_key_data *key_data,
2092 krb5_keyblock **keyblocks, int *n_keys)
2094 krb5_keyblock *keys;
2097 keys = (krb5_keyblock *) malloc(n_key_data*sizeof(krb5_keyblock));
2100 memset(keys, 0, n_key_data*sizeof(krb5_keyblock));
2102 for (i = 0; i < n_key_data; i++) {
2103 ret = krb5_dbe_decrypt_key_data(context, NULL, &key_data[i], &keys[i],
2106 for (; i >= 0; i--) {
2107 if (keys[i].contents) {
2108 memset (keys[i].contents, 0, keys[i].length);
2109 free( keys[i].contents );
2113 memset(keys, 0, n_key_data*sizeof(krb5_keyblock));
2121 *n_keys = n_key_data;
2127 * Function: kadm5_decrypt_key
2129 * Purpose: Retrieves and decrypts a principal key.
2133 * server_handle (r) kadm5 handle
2134 * entry (r) principal retrieved with kadm5_get_principal
2135 * ktype (r) enctype to search for, or -1 to ignore
2136 * stype (r) salt type to search for, or -1 to ignore
2137 * kvno (r) kvno to search for, -1 for max, 0 for max
2138 * only if it also matches ktype and stype
2139 * keyblock (w) keyblock to fill in
2140 * keysalt (w) keysalt to fill in, or NULL
2141 * kvnop (w) kvno to fill in, or NULL
2143 * Effects: Searches the key_data array of entry, which must have been
2144 * retrived with kadm5_get_principal with the KADM5_KEY_DATA mask, to
2145 * find a key with a specified enctype, salt type, and kvno in a
2146 * principal entry. If not found, return ENOENT. Otherwise, decrypt
2147 * it with the master key, and return the key in keyblock, the salt
2148 * in salttype, and the key version number in kvno.
2150 * If ktype or stype is -1, it is ignored for the search. If kvno is
2151 * -1, ktype and stype are ignored and the key with the max kvno is
2152 * returned. If kvno is 0, only the key with the max kvno is returned
2153 * and only if it matches the ktype and stype; otherwise, ENOENT is
2156 kadm5_ret_t kadm5_decrypt_key(void *server_handle,
2157 kadm5_principal_ent_t entry, krb5_int32
2158 ktype, krb5_int32 stype, krb5_int32
2159 kvno, krb5_keyblock *keyblock,
2160 krb5_keysalt *keysalt, int *kvnop)
2162 kadm5_server_handle_t handle = server_handle;
2163 krb5_db_entry dbent;
2164 krb5_key_data *key_data;
2165 krb5_keyblock *mkey_ptr;
2168 CHECK_HANDLE(server_handle);
2170 if (entry->n_key_data == 0 || entry->key_data == NULL)
2173 /* find_enctype only uses these two fields */
2174 dbent.n_key_data = entry->n_key_data;
2175 dbent.key_data = entry->key_data;
2176 if ((ret = krb5_dbe_find_enctype(handle->context, &dbent, ktype,
2177 stype, kvno, &key_data)))
2180 /* find_mkey only uses this field */
2181 dbent.tl_data = entry->tl_data;
2182 if ((ret = krb5_dbe_find_mkey(handle->context, &dbent, &mkey_ptr))) {
2183 /* try refreshing master key list */
2184 /* XXX it would nice if we had the mkvno here for optimization */
2185 if (krb5_db_fetch_mkey_list(handle->context, master_princ,
2186 &master_keyblock) == 0) {
2187 if ((ret = krb5_dbe_find_mkey(handle->context, &dbent,
2196 if ((ret = krb5_dbe_decrypt_key_data(handle->context, NULL, key_data,
2197 keyblock, keysalt)))
2201 * Coerce the enctype of the output keyblock in case we got an
2202 * inexact match on the enctype; this behavior will go away when
2203 * the key storage architecture gets redesigned for 1.3.
2206 keyblock->enctype = ktype;
2209 *kvnop = key_data->key_data_kvno;
2215 kadm5_purgekeys(void *server_handle,
2216 krb5_principal principal,
2219 kadm5_server_handle_t handle = server_handle;
2222 osa_princ_ent_rec adb;
2223 krb5_key_data *old_keydata;
2227 CHECK_HANDLE(server_handle);
2229 if (principal == NULL)
2232 ret = kdb_get_entry(handle, principal, &kdb, &adb);
2236 if (keepkvno <= 0) {
2237 keepkvno = krb5_db_get_key_data_kvno(handle->context, kdb->n_key_data,
2241 old_keydata = kdb->key_data;
2242 n_old_keydata = kdb->n_key_data;
2243 kdb->n_key_data = 0;
2244 kdb->key_data = krb5_db_alloc(handle->context, NULL,
2245 n_old_keydata * sizeof(krb5_key_data));
2246 if (kdb->key_data == NULL) {
2250 memset(kdb->key_data, 0, n_old_keydata * sizeof(krb5_key_data));
2251 for (i = 0, j = 0; i < n_old_keydata; i++) {
2252 if (old_keydata[i].key_data_kvno < keepkvno)
2255 /* Alias the key_data_contents pointers; we null them out in the
2256 * source array immediately after. */
2257 kdb->key_data[j] = old_keydata[i];
2258 for (k = 0; k < old_keydata[i].key_data_ver; k++) {
2259 old_keydata[i].key_data_contents[k] = NULL;
2263 kdb->n_key_data = j;
2264 cleanup_key_data(handle->context, n_old_keydata, old_keydata);
2266 kdb->mask = KADM5_KEY_DATA;
2267 ret = kdb_put_entry(handle, kdb, &adb);
2272 kdb_free_entry(handle, kdb, &adb);
2277 kadm5_get_strings(void *server_handle, krb5_principal principal,
2278 krb5_string_attr **strings_out, int *count_out)
2280 kadm5_server_handle_t handle = server_handle;
2282 krb5_db_entry *kdb = NULL;
2284 *strings_out = NULL;
2286 CHECK_HANDLE(server_handle);
2287 if (principal == NULL)
2290 ret = kdb_get_entry(handle, principal, &kdb, NULL);
2294 ret = krb5_dbe_get_strings(handle->context, kdb, strings_out, count_out);
2295 kdb_free_entry(handle, kdb, NULL);
2300 kadm5_set_string(void *server_handle, krb5_principal principal,
2301 const char *key, const char *value)
2303 kadm5_server_handle_t handle = server_handle;
2306 osa_princ_ent_rec adb;
2308 CHECK_HANDLE(server_handle);
2309 if (principal == NULL || key == NULL)
2312 ret = kdb_get_entry(handle, principal, &kdb, &adb);
2316 ret = krb5_dbe_set_string(handle->context, kdb, key, value);
2320 kdb->mask = KADM5_TL_DATA;
2321 ret = kdb_put_entry(handle, kdb, &adb);
2324 kdb_free_entry(handle, kdb, &adb);