1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
11 #include <kadm5/admin.h>
15 #include "server_internal.h"
18 #ifdef USE_PASSWORD_SERVER
24 #include <krb5/kadm5_hook_plugin.h>
27 #include <valgrind/memcheck.h>
29 #define VALGRIND_CHECK_DEFINED(LVALUE) ((void)0)
32 extern krb5_principal master_princ;
33 extern krb5_principal hist_princ;
34 extern krb5_keyblock master_keyblock;
35 extern krb5_keylist_node *master_keylist;
36 extern krb5_actkvno_node *active_mkey_list;
37 extern krb5_db_entry master_db;
39 static int decrypt_key_data(krb5_context context,
40 int n_key_data, krb5_key_data *key_data,
41 krb5_keyblock **keyblocks, int *n_keys);
43 static krb5_error_code
44 kadm5_copy_principal(krb5_context context, krb5_const_principal inprinc, krb5_principal *outprinc)
46 register krb5_principal tempprinc;
47 register int i, nelems;
49 tempprinc = (krb5_principal)krb5_db_alloc(context, NULL, sizeof(krb5_principal_data));
54 VALGRIND_CHECK_DEFINED(*inprinc);
55 *tempprinc = *inprinc;
57 nelems = (int) krb5_princ_size(context, inprinc);
58 tempprinc->data = krb5_db_alloc(context, NULL, nelems * sizeof(krb5_data));
59 if (tempprinc->data == 0) {
60 krb5_db_free(context, (char *)tempprinc);
64 for (i = 0; i < nelems; i++) {
65 unsigned int len = krb5_princ_component(context, inprinc, i)->length;
66 krb5_princ_component(context, tempprinc, i)->length = len;
67 if (((krb5_princ_component(context, tempprinc, i)->data =
68 krb5_db_alloc(context, NULL, len)) == 0) && len) {
70 krb5_db_free(context, krb5_princ_component(context, tempprinc, i)->data);
71 krb5_db_free (context, tempprinc->data);
72 krb5_db_free (context, tempprinc);
76 memcpy(krb5_princ_component(context, tempprinc, i)->data,
77 krb5_princ_component(context, inprinc, i)->data, len);
78 krb5_princ_component(context, tempprinc, i)->magic = KV5M_DATA;
81 tempprinc->realm.data =
82 krb5_db_alloc(context, NULL, tempprinc->realm.length = inprinc->realm.length);
83 if (!tempprinc->realm.data && tempprinc->realm.length) {
84 for (i = 0; i < nelems; i++)
85 krb5_db_free(context, krb5_princ_component(context, tempprinc, i)->data);
86 krb5_db_free(context, tempprinc->data);
87 krb5_db_free(context, tempprinc);
90 if (tempprinc->realm.length)
91 memcpy(tempprinc->realm.data, inprinc->realm.data,
92 inprinc->realm.length);
94 *outprinc = tempprinc;
99 kadm5_free_principal(krb5_context context, krb5_principal val)
101 register krb5_int32 i;
107 i = krb5_princ_size(context, val);
109 krb5_db_free(context, krb5_princ_component(context, val, i)->data);
110 krb5_db_free(context, val->data);
113 krb5_db_free(context, val->realm.data);
114 krb5_db_free(context, val);
118 * XXX Functions that ought to be in libkrb5.a, but aren't.
120 kadm5_ret_t krb5_copy_key_data_contents(context, from, to)
121 krb5_context context;
122 krb5_key_data *from, *to;
128 idx = (from->key_data_ver == 1 ? 1 : 2);
130 for (i = 0; i < idx; i++) {
131 if ( from->key_data_length[i] ) {
132 to->key_data_contents[i] = malloc(from->key_data_length[i]);
133 if (to->key_data_contents[i] == NULL) {
134 for (i = 0; i < idx; i++) {
135 if (to->key_data_contents[i]) {
136 memset(to->key_data_contents[i], 0,
137 to->key_data_length[i]);
138 free(to->key_data_contents[i]);
143 memcpy(to->key_data_contents[i], from->key_data_contents[i],
144 from->key_data_length[i]);
150 static krb5_tl_data *dup_tl_data(krb5_tl_data *tl)
154 n = (krb5_tl_data *) malloc(sizeof(krb5_tl_data));
157 n->tl_data_contents = malloc(tl->tl_data_length);
158 if (n->tl_data_contents == NULL) {
162 memcpy(n->tl_data_contents, tl->tl_data_contents, tl->tl_data_length);
163 n->tl_data_type = tl->tl_data_type;
164 n->tl_data_length = tl->tl_data_length;
165 n->tl_data_next = NULL;
169 /* This is in lib/kdb/kdb_cpw.c, but is static */
170 static void cleanup_key_data(context, count, data)
171 krb5_context context;
173 krb5_key_data * data;
177 for (i = 0; i < count; i++)
178 for (j = 0; j < data[i].key_data_ver; j++)
179 if (data[i].key_data_length[j])
180 krb5_db_free(context, data[i].key_data_contents[j]);
181 krb5_db_free(context, data);
185 * Set *passptr to NULL if the request looks like the first part of a krb5 1.6
186 * addprinc -randkey operation. The krb5 1.6 dummy password for these requests
187 * was invalid UTF-8, which runs afoul of the arcfour string-to-key.
190 check_1_6_dummy(kadm5_principal_ent_t entry, long mask,
191 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, char **passptr)
194 char *password = *passptr;
196 /* Old-style randkey operations disallowed tickets to start. */
197 if (!(mask & KADM5_ATTRIBUTES) ||
198 !(entry->attributes & KRB5_KDB_DISALLOW_ALL_TIX))
201 /* The 1.6 dummy password was the octets 1..255. */
202 for (i = 0; (unsigned char) password[i] == i + 1; i++);
203 if (password[i] != '\0' || i != 255)
206 /* This will make the caller use a random password instead. */
211 kadm5_create_principal(void *server_handle,
212 kadm5_principal_ent_t entry, long mask,
216 kadm5_create_principal_3(server_handle, entry, mask,
220 kadm5_create_principal_3(void *server_handle,
221 kadm5_principal_ent_t entry, long mask,
222 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
226 osa_princ_ent_rec adb;
227 kadm5_policy_ent_rec polent;
228 krb5_boolean have_polent = FALSE;
230 krb5_tl_data *tl_data_orig, *tl_data_tail;
232 kadm5_server_handle_t handle = server_handle;
233 krb5_keyblock *act_mkey;
236 CHECK_HANDLE(server_handle);
238 krb5_clear_error_message(handle->context);
240 check_1_6_dummy(entry, mask, n_ks_tuple, ks_tuple, &password);
243 * Argument sanity checking, and opening up the DB
245 if(!(mask & KADM5_PRINCIPAL) || (mask & KADM5_MOD_NAME) ||
246 (mask & KADM5_MOD_TIME) || (mask & KADM5_LAST_PWD_CHANGE) ||
247 (mask & KADM5_MKVNO) || (mask & KADM5_POLICY_CLR) ||
248 (mask & KADM5_AUX_ATTRIBUTES) || (mask & KADM5_KEY_DATA) ||
249 (mask & KADM5_LAST_SUCCESS) || (mask & KADM5_LAST_FAILED) ||
250 (mask & KADM5_FAIL_AUTH_COUNT))
251 return KADM5_BAD_MASK;
252 if((mask & ~ALL_PRINC_MASK))
253 return KADM5_BAD_MASK;
257 /* Use default keysalts if caller did not provide any. */
258 if (n_ks_tuple == 0) {
259 ks_tuple = handle->params.keysalts;
260 n_ks_tuple = handle->params.num_keysalts;
264 * Check to see if the principal exists
266 ret = kdb_get_entry(handle, entry->principal, &kdb, &adb);
269 case KADM5_UNK_PRINC:
272 kdb_free_entry(handle, kdb, &adb);
278 kdb = krb5_db_alloc(handle->context, NULL, sizeof(*kdb));
281 memset(kdb, 0, sizeof(*kdb));
282 memset(&adb, 0, sizeof(osa_princ_ent_rec));
285 * If a policy was specified, load it.
286 * If we can not find the one specified return an error
288 if ((mask & KADM5_POLICY)) {
289 if ((ret = kadm5_get_policy(handle->lhandle, entry->policy,
290 &polent)) != KADM5_OK) {
292 ret = KADM5_BAD_POLICY;
299 ret = passwd_check(handle, password, have_polent ? &polent : NULL,
305 * Start populating the various DB fields, using the
306 * "defaults" for fields that were not specified by the
309 if ((ret = krb5_timeofday(handle->context, &now)))
312 kdb->magic = KRB5_KDB_MAGIC_NUMBER;
313 kdb->len = KRB5_KDB_V1_BASE_LENGTH; /* gag me with a chainsaw */
315 if ((mask & KADM5_ATTRIBUTES))
316 kdb->attributes = entry->attributes;
318 kdb->attributes = handle->params.flags;
320 if ((mask & KADM5_MAX_LIFE))
321 kdb->max_life = entry->max_life;
323 kdb->max_life = handle->params.max_life;
325 if (mask & KADM5_MAX_RLIFE)
326 kdb->max_renewable_life = entry->max_renewable_life;
328 kdb->max_renewable_life = handle->params.max_rlife;
330 if ((mask & KADM5_PRINC_EXPIRE_TIME))
331 kdb->expiration = entry->princ_expire_time;
333 kdb->expiration = handle->params.expiration;
335 kdb->pw_expiration = 0;
337 if(polent.pw_max_life)
338 kdb->pw_expiration = now + polent.pw_max_life;
340 kdb->pw_expiration = 0;
342 if ((mask & KADM5_PW_EXPIRATION))
343 kdb->pw_expiration = entry->pw_expiration;
345 kdb->last_success = 0;
346 kdb->last_failed = 0;
347 kdb->fail_auth_count = 0;
349 /* this is kind of gross, but in order to free the tl data, I need
350 to free the entire kdb entry, and that will try to free the
353 if ((ret = kadm5_copy_principal(handle->context,
354 entry->principal, &(kdb->princ))))
357 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, kdb, now)))
360 if (mask & KADM5_TL_DATA) {
361 /* splice entry->tl_data onto the front of kdb->tl_data */
362 tl_data_orig = kdb->tl_data;
363 for (tl_data_tail = entry->tl_data; tl_data_tail;
364 tl_data_tail = tl_data_tail->tl_data_next)
366 ret = krb5_dbe_update_tl_data(handle->context, kdb, tl_data_tail);
372 /* initialize the keys */
374 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
375 active_mkey_list, &act_kvno, &act_mkey);
380 ret = krb5_dbe_cpw(handle->context, act_mkey, ks_tuple, n_ks_tuple,
381 password, (mask & KADM5_KVNO)?entry->kvno:1,
384 /* Null password means create with random key (new in 1.8). */
385 ret = krb5_dbe_crk(handle->context, &master_keyblock,
386 ks_tuple, n_ks_tuple, FALSE, kdb);
391 /* Record the master key VNO used to encrypt this entry's keys */
392 ret = krb5_dbe_update_mkvno(handle->context, kdb, act_kvno);
396 ret = k5_kadm5_hook_create(handle->context, handle->hook_handles,
397 KADM5_HOOK_STAGE_PRECOMMIT, entry, mask,
398 n_ks_tuple, ks_tuple, password);
402 /* populate the admin-server-specific fields. In the OV server,
403 this used to be in a separate database. Since there's already
404 marshalling code for the admin fields, to keep things simple,
405 I'm going to keep it, and make all the admin stuff occupy a
406 single tl_data record, */
408 adb.admin_history_kvno = INITIAL_HIST_KVNO;
410 adb.aux_attributes = KADM5_POLICY;
412 /* this does *not* need to be strdup'ed, because adb is xdr */
413 /* encoded in osa_adb_create_princ, and not ever freed */
415 adb.policy = entry->policy;
418 /* increment the policy ref count, if any */
421 polent.policy_refcnt++;
422 if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent,
428 /* In all cases key and the principal data is set, let the database provider know */
429 kdb->mask = mask | KADM5_KEY_DATA | KADM5_PRINCIPAL ;
431 /* store the new db entry */
432 ret = kdb_put_entry(handle, kdb, &adb);
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,
449 (void) k5_kadm5_hook_create(handle->context, handle->hook_handles,
450 KADM5_HOOK_STAGE_POSTCOMMIT, entry, mask,
451 n_ks_tuple, ks_tuple, password);
454 krb5_db_free_principal(handle->context, kdb);
456 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
462 kadm5_delete_principal(void *server_handle, krb5_principal principal)
465 kadm5_policy_ent_rec polent;
467 osa_princ_ent_rec adb;
468 kadm5_server_handle_t handle = server_handle;
470 CHECK_HANDLE(server_handle);
472 krb5_clear_error_message(handle->context);
474 if (principal == NULL)
477 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
479 ret = k5_kadm5_hook_remove(handle->context, handle->hook_handles,
480 KADM5_HOOK_STAGE_PRECOMMIT, principal);
482 kdb_free_entry(handle, kdb, &adb);
486 if ((adb.aux_attributes & KADM5_POLICY)) {
487 if ((ret = kadm5_get_policy(handle->lhandle,
488 adb.policy, &polent))
490 polent.policy_refcnt--;
491 if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent,
494 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
495 kdb_free_entry(handle, kdb, &adb);
499 if ((ret = kadm5_free_policy_ent(handle->lhandle, &polent))) {
500 kdb_free_entry(handle, kdb, &adb);
505 ret = kdb_delete_entry(handle, principal);
507 kdb_free_entry(handle, kdb, &adb);
510 (void) k5_kadm5_hook_remove(handle->context,
511 handle->hook_handles,
512 KADM5_HOOK_STAGE_POSTCOMMIT, principal);
518 kadm5_modify_principal(void *server_handle,
519 kadm5_principal_ent_t entry, long mask)
522 kadm5_policy_ent_rec npol, opol;
523 int have_npol = 0, have_opol = 0;
525 krb5_tl_data *tl_data_orig;
526 osa_princ_ent_rec adb;
527 kadm5_server_handle_t handle = server_handle;
529 CHECK_HANDLE(server_handle);
531 krb5_clear_error_message(handle->context);
533 if((mask & KADM5_PRINCIPAL) || (mask & KADM5_LAST_PWD_CHANGE) ||
534 (mask & KADM5_MOD_TIME) || (mask & KADM5_MOD_NAME) ||
535 (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) ||
536 (mask & KADM5_KEY_DATA) || (mask & KADM5_LAST_SUCCESS) ||
537 (mask & KADM5_LAST_FAILED))
538 return KADM5_BAD_MASK;
539 if((mask & ~ALL_PRINC_MASK))
540 return KADM5_BAD_MASK;
541 if((mask & KADM5_POLICY) && (mask & KADM5_POLICY_CLR))
542 return KADM5_BAD_MASK;
543 if(entry == (kadm5_principal_ent_t) NULL)
545 if (mask & KADM5_TL_DATA) {
546 tl_data_orig = entry->tl_data;
547 while (tl_data_orig) {
548 if (tl_data_orig->tl_data_type < 256)
549 return KADM5_BAD_TL_TYPE;
550 tl_data_orig = tl_data_orig->tl_data_next;
554 ret = kdb_get_entry(handle, entry->principal, &kdb, &adb);
559 * This is pretty much the same as create ...
562 if ((mask & KADM5_POLICY)) {
563 /* get the new policy */
564 ret = kadm5_get_policy(handle->lhandle, entry->policy, &npol);
568 ret = KADM5_BAD_POLICY;
570 case KADM5_UNK_POLICY:
571 case KADM5_BAD_POLICY:
572 ret = KADM5_UNK_POLICY;
579 /* if we already have a policy, get it to decrement the refcnt */
580 if(adb.aux_attributes & KADM5_POLICY) {
581 /* ... but not if the old and new are the same */
582 if(strcmp(adb.policy, entry->policy)) {
583 ret = kadm5_get_policy(handle->lhandle,
587 case KADM5_BAD_POLICY:
588 case KADM5_UNK_POLICY:
592 opol.policy_refcnt--;
598 npol.policy_refcnt++;
600 } else npol.policy_refcnt++;
602 /* set us up to use the new policy */
603 adb.aux_attributes |= KADM5_POLICY;
606 adb.policy = strdup(entry->policy);
608 /* set pw_max_life based on new policy */
609 if (npol.pw_max_life) {
610 ret = krb5_dbe_lookup_last_pwd_change(handle->context, kdb,
611 &(kdb->pw_expiration));
614 kdb->pw_expiration += npol.pw_max_life;
616 kdb->pw_expiration = 0;
620 if ((mask & KADM5_POLICY_CLR) &&
621 (adb.aux_attributes & KADM5_POLICY)) {
622 ret = kadm5_get_policy(handle->lhandle, adb.policy, &opol);
625 case KADM5_BAD_POLICY:
626 case KADM5_UNK_POLICY:
635 adb.aux_attributes &= ~KADM5_POLICY;
636 kdb->pw_expiration = 0;
637 opol.policy_refcnt--;
645 if (((mask & KADM5_POLICY) || (mask & KADM5_POLICY_CLR)) &&
648 kadm5_modify_policy_internal(handle->lhandle, &opol,
649 KADM5_REF_COUNT))) ||
652 kadm5_modify_policy_internal(handle->lhandle, &npol,
656 if ((mask & KADM5_ATTRIBUTES))
657 kdb->attributes = entry->attributes;
658 if ((mask & KADM5_MAX_LIFE))
659 kdb->max_life = entry->max_life;
660 if ((mask & KADM5_PRINC_EXPIRE_TIME))
661 kdb->expiration = entry->princ_expire_time;
662 if (mask & KADM5_PW_EXPIRATION)
663 kdb->pw_expiration = entry->pw_expiration;
664 if (mask & KADM5_MAX_RLIFE)
665 kdb->max_renewable_life = entry->max_renewable_life;
667 if((mask & KADM5_KVNO)) {
668 for (i = 0; i < kdb->n_key_data; i++)
669 kdb->key_data[i].key_data_kvno = entry->kvno;
672 if (mask & KADM5_TL_DATA) {
675 /* may have to change the version number of the API. Updates the list with the given tl_data rather than over-writting */
677 for (tl = entry->tl_data; tl;
678 tl = tl->tl_data_next)
680 ret = krb5_dbe_update_tl_data(handle->context, kdb, tl);
689 * Setting entry->fail_auth_count to 0 can be used to manually unlock
690 * an account. It is not possible to set fail_auth_count to any other
691 * value using kadmin.
693 if (mask & KADM5_FAIL_AUTH_COUNT) {
694 if (entry->fail_auth_count != 0) {
695 ret = KADM5_BAD_SERVER_PARAMS;
699 kdb->fail_auth_count = 0;
702 /* let the mask propagate to the database provider */
705 ret = k5_kadm5_hook_modify(handle->context, handle->hook_handles,
706 KADM5_HOOK_STAGE_PRECOMMIT, entry, mask);
710 ret = kdb_put_entry(handle, kdb, &adb);
712 (void) k5_kadm5_hook_modify(handle->context, handle->hook_handles,
713 KADM5_HOOK_STAGE_POSTCOMMIT, entry, mask);
718 ret2 = kadm5_free_policy_ent(handle->lhandle, &opol);
719 ret = ret ? ret : ret2;
722 ret2 = kadm5_free_policy_ent(handle->lhandle, &npol);
723 ret = ret ? ret : ret2;
725 kdb_free_entry(handle, kdb, &adb);
730 kadm5_rename_principal(void *server_handle,
731 krb5_principal source, krb5_principal target)
734 osa_princ_ent_rec adb;
736 kadm5_server_handle_t handle = server_handle;
738 CHECK_HANDLE(server_handle);
740 krb5_clear_error_message(handle->context);
742 if (source == NULL || target == NULL)
745 if ((ret = kdb_get_entry(handle, target, &kdb, &adb)) == 0) {
746 kdb_free_entry(handle, kdb, &adb);
750 if ((ret = kdb_get_entry(handle, source, &kdb, &adb)))
753 /* this is kinda gross, but unavoidable */
755 for (i=0; i<kdb->n_key_data; i++) {
756 if ((kdb->key_data[i].key_data_ver == 1) ||
757 (kdb->key_data[i].key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL)) {
758 ret = KADM5_NO_RENAME_SALT;
763 kadm5_free_principal(handle->context, kdb->princ);
764 ret = kadm5_copy_principal(handle->context, target, &kdb->princ);
766 kdb->princ = NULL; /* so freeing the dbe doesn't lose */
770 if ((ret = kdb_put_entry(handle, kdb, &adb)))
773 ret = kdb_delete_entry(handle, source);
776 kdb_free_entry(handle, kdb, &adb);
781 kadm5_get_principal(void *server_handle, krb5_principal principal,
782 kadm5_principal_ent_t entry,
786 osa_princ_ent_rec adb;
787 krb5_error_code ret = 0;
790 kadm5_server_handle_t handle = server_handle;
792 CHECK_HANDLE(server_handle);
794 krb5_clear_error_message(handle->context);
797 * In version 1, all the defined fields are always returned.
798 * entry is a pointer to a kadm5_principal_ent_t_v1 that should be
799 * filled with allocated memory.
803 memset(entry, 0, sizeof(*entry));
805 if (principal == NULL)
808 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
811 if ((mask & KADM5_POLICY) &&
812 adb.policy && (adb.aux_attributes & KADM5_POLICY)) {
813 if ((entry->policy = strdup(adb.policy)) == NULL) {
819 if (mask & KADM5_AUX_ATTRIBUTES)
820 entry->aux_attributes = adb.aux_attributes;
822 if ((mask & KADM5_PRINCIPAL) &&
823 (ret = krb5_copy_principal(handle->context, kdb->princ,
824 &entry->principal))) {
828 if (mask & KADM5_PRINC_EXPIRE_TIME)
829 entry->princ_expire_time = kdb->expiration;
831 if ((mask & KADM5_LAST_PWD_CHANGE) &&
832 (ret = krb5_dbe_lookup_last_pwd_change(handle->context, kdb,
833 &(entry->last_pwd_change)))) {
837 if (mask & KADM5_PW_EXPIRATION)
838 entry->pw_expiration = kdb->pw_expiration;
839 if (mask & KADM5_MAX_LIFE)
840 entry->max_life = kdb->max_life;
842 /* this is a little non-sensical because the function returns two */
843 /* values that must be checked separately against the mask */
844 if ((mask & KADM5_MOD_NAME) || (mask & KADM5_MOD_TIME)) {
845 ret = krb5_dbe_lookup_mod_princ_data(handle->context, kdb,
852 if (! (mask & KADM5_MOD_TIME))
854 if (! (mask & KADM5_MOD_NAME)) {
855 krb5_free_principal(handle->context, entry->mod_name);
856 entry->mod_name = NULL;
860 if (mask & KADM5_ATTRIBUTES)
861 entry->attributes = kdb->attributes;
863 if (mask & KADM5_KVNO)
864 for (entry->kvno = 0, i=0; i<kdb->n_key_data; i++)
865 if ((krb5_kvno) kdb->key_data[i].key_data_kvno > entry->kvno)
866 entry->kvno = kdb->key_data[i].key_data_kvno;
868 if (mask & KADM5_MKVNO) {
869 ret = krb5_dbe_get_mkvno(handle->context, kdb, master_keylist,
875 if (mask & KADM5_MAX_RLIFE)
876 entry->max_renewable_life = kdb->max_renewable_life;
877 if (mask & KADM5_LAST_SUCCESS)
878 entry->last_success = kdb->last_success;
879 if (mask & KADM5_LAST_FAILED)
880 entry->last_failed = kdb->last_failed;
881 if (mask & KADM5_FAIL_AUTH_COUNT)
882 entry->fail_auth_count = kdb->fail_auth_count;
883 if (mask & KADM5_TL_DATA) {
884 krb5_tl_data *tl, *tl2;
886 entry->tl_data = NULL;
890 if (tl->tl_data_type > 255) {
891 if ((tl2 = dup_tl_data(tl)) == NULL) {
895 tl2->tl_data_next = entry->tl_data;
896 entry->tl_data = tl2;
900 tl = tl->tl_data_next;
903 if (mask & KADM5_KEY_DATA) {
904 entry->n_key_data = kdb->n_key_data;
905 if(entry->n_key_data) {
906 entry->key_data = malloc(entry->n_key_data*sizeof(krb5_key_data));
907 if (entry->key_data == NULL) {
912 entry->key_data = NULL;
914 for (i = 0; i < entry->n_key_data; i++)
915 ret = krb5_copy_key_data_contents(handle->context,
917 &entry->key_data[i]);
925 if (ret && entry->principal) {
926 krb5_free_principal(handle->context, entry->principal);
927 entry->principal = NULL;
929 kdb_free_entry(handle, kdb, &adb);
935 * Function: check_pw_reuse
937 * Purpose: Check if a key appears in a list of keys, in order to
938 * enforce password history.
942 * context (r) the krb5 context
943 * hist_keyblock (r) the key that hist_key_data is
945 * n_new_key_data (r) length of new_key_data
946 * new_key_data (r) keys to check against
947 * pw_hist_data, encrypted in hist_keyblock
948 * n_pw_hist_data (r) length of pw_hist_data
949 * pw_hist_data (r) passwords to check new_key_data against
952 * For each new_key in new_key_data:
953 * decrypt new_key with the master_keyblock
954 * for each password in pw_hist_data:
955 * for each hist_key in password:
956 * decrypt hist_key with hist_keyblock
957 * compare the new_key and hist_key
959 * Returns krb5 errors, KADM5_PASS_RESUSE if a key in
960 * new_key_data is the same as a key in pw_hist_data, or 0.
963 check_pw_reuse(krb5_context context,
964 krb5_keyblock *hist_keyblock,
965 int n_new_key_data, krb5_key_data *new_key_data,
966 unsigned int n_pw_hist_data, osa_pw_hist_ent *pw_hist_data)
968 unsigned int x, y, z;
969 krb5_keyblock newkey, histkey;
972 assert (n_new_key_data >= 0);
973 for (x = 0; x < (unsigned) n_new_key_data; x++) {
974 ret = krb5_dbe_decrypt_key_data(context, NULL, &(new_key_data[x]),
978 for (y = 0; y < n_pw_hist_data; y++) {
979 for (z = 0; z < (unsigned int) pw_hist_data[y].n_key_data; z++) {
980 ret = krb5_dbe_decrypt_key_data(context, hist_keyblock,
981 &pw_hist_data[y].key_data[z],
986 if ((newkey.length == histkey.length) &&
987 (newkey.enctype == histkey.enctype) &&
988 (memcmp(newkey.contents, histkey.contents,
989 histkey.length) == 0)) {
990 krb5_free_keyblock_contents(context, &histkey);
991 krb5_free_keyblock_contents(context, &newkey);
993 return(KADM5_PASS_REUSE);
995 krb5_free_keyblock_contents(context, &histkey);
998 krb5_free_keyblock_contents(context, &newkey);
1005 * Function: create_history_entry
1007 * Purpose: Creates a password history entry from an array of
1012 * context (r) krb5_context to use
1013 * mkey (r) master keyblock to decrypt key data with
1014 * hist_key (r) history keyblock to encrypt key data with
1015 * n_key_data (r) number of elements in key_data
1016 * key_data (r) keys to add to the history entry
1017 * hist (w) history entry to fill in
1021 * hist->key_data is allocated to store n_key_data key_datas. Each
1022 * element of key_data is decrypted with master_keyblock, re-encrypted
1023 * in hist_key, and added to hist->key_data. hist->n_key_data is
1024 * set to n_key_data.
1027 int create_history_entry(krb5_context context,
1028 krb5_keyblock *hist_key, int n_key_data,
1029 krb5_key_data *key_data, osa_pw_hist_ent *hist)
1035 hist->key_data = (krb5_key_data*)malloc(n_key_data*sizeof(krb5_key_data));
1036 if (hist->key_data == NULL)
1038 memset(hist->key_data, 0, n_key_data*sizeof(krb5_key_data));
1040 for (i = 0; i < n_key_data; i++) {
1041 ret = krb5_dbe_decrypt_key_data(context, NULL, &key_data[i], &key,
1046 ret = krb5_dbe_encrypt_key_data(context, hist_key, &key, &salt,
1047 key_data[i].key_data_kvno,
1048 &hist->key_data[i]);
1052 krb5_free_keyblock_contents(context, &key);
1053 /* krb5_free_keysalt(context, &salt); */
1056 hist->n_key_data = n_key_data;
1061 void free_history_entry(krb5_context context, osa_pw_hist_ent *hist)
1065 for (i = 0; i < hist->n_key_data; i++)
1066 krb5_free_key_data_contents(context, &hist->key_data[i]);
1067 free(hist->key_data);
1071 * Function: add_to_history
1073 * Purpose: Adds a password to a principal's password history.
1077 * context (r) krb5_context to use
1078 * hist_kvno (r) kvno of current history key
1079 * adb (r/w) admin principal entry to add keys to
1080 * pol (r) adb's policy
1081 * pw (r) keys for the password to add to adb's key history
1085 * add_to_history adds a single password to adb's password history.
1086 * pw contains n_key_data keys in its key_data, in storage should be
1087 * allocated but not freed by the caller (XXX blech!).
1089 * This function maintains adb->old_keys as a circular queue. It
1090 * starts empty, and grows each time this function is called until it
1091 * is pol->pw_history_num items long. adb->old_key_len holds the
1092 * number of allocated entries in the array, and must therefore be [0,
1093 * pol->pw_history_num). adb->old_key_next is the index into the
1094 * array where the next element should be written, and must be [0,
1095 * adb->old_key_len).
1097 static kadm5_ret_t add_to_history(krb5_context context,
1098 krb5_kvno hist_kvno,
1099 osa_princ_ent_t adb,
1100 kadm5_policy_ent_t pol,
1101 osa_pw_hist_ent *pw)
1103 osa_pw_hist_ent *histp;
1105 unsigned int i, knext, nkeys;
1107 nhist = pol->pw_history_num;
1108 /* A history of 1 means just check the current password */
1112 if (adb->admin_history_kvno != hist_kvno) {
1113 /* The history key has changed since the last password change, so we
1114 * have to reset the password history. */
1115 free(adb->old_keys);
1116 adb->old_keys = NULL;
1117 adb->old_key_len = 0;
1118 adb->old_key_next = 0;
1119 adb->admin_history_kvno = hist_kvno;
1122 nkeys = adb->old_key_len;
1123 knext = adb->old_key_next;
1124 /* resize the adb->old_keys array if necessary */
1125 if (nkeys + 1 < nhist) {
1126 if (adb->old_keys == NULL) {
1127 adb->old_keys = (osa_pw_hist_ent *)
1128 malloc((nkeys + 1) * sizeof (osa_pw_hist_ent));
1130 adb->old_keys = (osa_pw_hist_ent *)
1131 realloc(adb->old_keys,
1132 (nkeys + 1) * sizeof (osa_pw_hist_ent));
1134 if (adb->old_keys == NULL)
1137 memset(&adb->old_keys[nkeys], 0, sizeof(osa_pw_hist_ent));
1138 nkeys = ++adb->old_key_len;
1140 * To avoid losing old keys, shift forward each entry after
1143 for (i = nkeys - 1; i > knext; i--) {
1144 adb->old_keys[i] = adb->old_keys[i - 1];
1146 memset(&adb->old_keys[knext], 0, sizeof(osa_pw_hist_ent));
1147 } else if (nkeys + 1 > nhist) {
1149 * The policy must have changed! Shrink the array.
1150 * Can't simply realloc() down, since it might be wrapped.
1151 * To understand the arithmetic below, note that we are
1152 * copying into new positions 0 .. N-1 from old positions
1153 * old_key_next-N .. old_key_next-1, modulo old_key_len,
1154 * where N = pw_history_num - 1 is the length of the
1155 * shortened list. Matt Crawford, FNAL
1158 * M = adb->old_key_len, N = pol->pw_history_num - 1
1160 * tmp[0] .. tmp[N-1] = old[(knext-N)%M] .. old[(knext-1)%M]
1165 tmp = (osa_pw_hist_ent *)
1166 malloc((nhist - 1) * sizeof (osa_pw_hist_ent));
1169 for (i = 0; i < nhist - 1; i++) {
1171 * Add nkeys once before taking remainder to avoid
1174 j = (i + nkeys + knext - (nhist - 1)) % nkeys;
1175 tmp[i] = adb->old_keys[j];
1177 /* Now free the ones we don't keep (the oldest ones) */
1178 for (i = 0; i < nkeys - (nhist - 1); i++) {
1179 j = (i + nkeys + knext) % nkeys;
1180 histp = &adb->old_keys[j];
1181 for (j = 0; j < histp->n_key_data; j++) {
1182 krb5_free_key_data_contents(context, &histp->key_data[j]);
1184 free(histp->key_data);
1186 free(adb->old_keys);
1187 adb->old_keys = tmp;
1188 nkeys = adb->old_key_len = nhist - 1;
1189 knext = adb->old_key_next = 0;
1193 * If nhist decreased since the last password change, and nkeys+1
1194 * is less than the previous nhist, it is possible for knext to
1195 * index into unallocated space. This condition would not be
1196 * caught by the resizing code above.
1198 if (knext + 1 > nkeys)
1199 knext = adb->old_key_next = 0;
1200 /* free the old pw history entry if it contains data */
1201 histp = &adb->old_keys[knext];
1202 for (i = 0; i < (unsigned int) histp->n_key_data; i++)
1203 krb5_free_key_data_contents(context, &histp->key_data[i]);
1204 free(histp->key_data);
1206 /* store the new entry */
1207 adb->old_keys[knext] = *pw;
1209 /* update the next pointer */
1210 if (++adb->old_key_next == nhist - 1)
1211 adb->old_key_next = 0;
1216 /* FIXME: don't use global variable for this */
1217 krb5_boolean use_password_server = 0;
1219 #ifdef USE_PASSWORD_SERVER
1221 kadm5_use_password_server (void)
1223 return use_password_server;
1228 kadm5_set_use_password_server (void)
1230 use_password_server = 1;
1233 #ifdef USE_PASSWORD_SERVER
1236 * kadm5_launch_task () runs a program (task_path) to synchronize the
1237 * Apple password server with the Kerberos database. Password server
1238 * programs can receive arguments on the command line (task_argv)
1239 * and a block of data via stdin (data_buffer).
1241 * Because a failure to communicate with the tool results in the
1242 * password server falling out of sync with the database,
1243 * kadm5_launch_task() always fails if it can't talk to the tool.
1247 kadm5_launch_task (krb5_context context,
1248 const char *task_path, char * const task_argv[],
1254 ret = pipe (data_pipe);
1259 pid_t pid = fork ();
1262 close (data_pipe[0]);
1263 close (data_pipe[1]);
1264 } else if (pid == 0) {
1267 if (dup2 (data_pipe[0], STDIN_FILENO) == -1)
1270 close (data_pipe[0]);
1271 close (data_pipe[1]);
1273 execv (task_path, task_argv);
1275 _exit (1); /* Fail if execv fails */
1282 close (data_pipe[0]);
1284 /* Write out the buffer to the child, add \n */
1286 if (krb5_net_write (context, data_pipe[1], buffer, strlen (buffer)) < 0
1287 || krb5_net_write (context, data_pipe[1], "\n", 1) < 0)
1289 /* kill the child to make sure waitpid() won't hang later */
1291 kill (pid, SIGKILL);
1294 close (data_pipe[1]);
1296 waitpid (pid, &status, 0);
1299 if (WIFEXITED (status)) {
1300 /* child read password and exited. Check the return value. */
1301 if ((WEXITSTATUS (status) != 0) && (WEXITSTATUS (status) != 252)) {
1302 ret = KRB5KDC_ERR_POLICY; /* password change rejected */
1305 /* child read password but crashed or was killed */
1306 ret = KRB5KRB_ERR_GENERIC; /* FIXME: better error */
1318 kadm5_chpass_principal(void *server_handle,
1319 krb5_principal principal, char *password)
1322 kadm5_chpass_principal_3(server_handle, principal, FALSE,
1327 kadm5_chpass_principal_3(void *server_handle,
1328 krb5_principal principal, krb5_boolean keepold,
1329 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1333 kadm5_policy_ent_rec pol;
1334 osa_princ_ent_rec adb;
1335 krb5_db_entry *kdb, *kdb_save;
1336 int ret, ret2, last_pwd, hist_added;
1338 kadm5_server_handle_t handle = server_handle;
1339 osa_pw_hist_ent hist;
1340 krb5_keyblock *act_mkey, hist_keyblock;
1341 krb5_kvno act_kvno, hist_kvno;
1343 CHECK_HANDLE(server_handle);
1345 krb5_clear_error_message(handle->context);
1348 memset(&hist, 0, sizeof(hist));
1349 memset(&hist_keyblock, 0, sizeof(hist_keyblock));
1351 if (principal == NULL || password == NULL)
1353 if ((krb5_principal_compare(handle->context,
1354 principal, hist_princ)) == TRUE)
1355 return KADM5_PROTECT_PRINCIPAL;
1357 /* Use default keysalts if caller did not provide any. */
1358 if (n_ks_tuple == 0) {
1359 ks_tuple = handle->params.keysalts;
1360 n_ks_tuple = handle->params.num_keysalts;
1363 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1366 /* we are going to need the current keys after the new keys are set */
1367 if ((ret = kdb_get_entry(handle, principal, &kdb_save, NULL))) {
1368 kdb_free_entry(handle, kdb, &adb);
1372 if ((adb.aux_attributes & KADM5_POLICY)) {
1373 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &pol)))
1378 if ((ret = passwd_check(handle, password, have_pol ? &pol : NULL,
1382 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
1383 active_mkey_list, &act_kvno, &act_mkey);
1387 ret = krb5_dbe_cpw(handle->context, act_mkey, ks_tuple, n_ks_tuple,
1388 password, 0 /* increment kvno */,
1393 ret = krb5_dbe_update_mkvno(handle->context, kdb, act_kvno);
1397 kdb->attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1399 ret = krb5_timeofday(handle->context, &now);
1403 if ((adb.aux_attributes & KADM5_POLICY)) {
1404 /* the policy was loaded before */
1406 ret = krb5_dbe_lookup_last_pwd_change(handle->context, kdb, &last_pwd);
1412 * The spec says this check is overridden if the caller has
1413 * modify privilege. The admin server therefore makes this
1414 * check itself (in chpass_principal_wrapper, misc.c). A
1415 * local caller implicitly has all authorization bits.
1417 if ((now - last_pwd) < pol.pw_min_life &&
1418 !(kdb->attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1419 ret = KADM5_PASS_TOOSOON;
1424 ret = kdb_get_hist_key(handle, &hist_keyblock, &hist_kvno);
1428 ret = create_history_entry(handle->context,
1430 kdb_save->n_key_data,
1431 kdb_save->key_data, &hist);
1435 ret = check_pw_reuse(handle->context, &hist_keyblock,
1436 kdb->n_key_data, kdb->key_data,
1441 if (pol.pw_history_num > 1) {
1442 /* If hist_kvno has changed since the last password change, we
1443 * can't check the history. */
1444 if (adb.admin_history_kvno == hist_kvno) {
1445 ret = check_pw_reuse(handle->context, &hist_keyblock,
1446 kdb->n_key_data, kdb->key_data,
1447 adb.old_key_len, adb.old_keys);
1452 ret = add_to_history(handle->context, hist_kvno, &adb, &pol,
1459 if (pol.pw_max_life)
1460 kdb->pw_expiration = now + pol.pw_max_life;
1462 kdb->pw_expiration = 0;
1464 kdb->pw_expiration = 0;
1467 #ifdef USE_PASSWORD_SERVER
1468 if (kadm5_use_password_server () &&
1469 (krb5_princ_size (handle->context, principal) == 1)) {
1470 krb5_data *princ = krb5_princ_component (handle->context, principal, 0);
1471 const char *path = "/usr/sbin/mkpassdb";
1472 char *argv[] = { "mkpassdb", "-setpassword", NULL, NULL };
1473 char *pstring = NULL;
1476 pstring = malloc ((princ->length + 1) * sizeof (char));
1477 if (pstring == NULL) { ret = ENOMEM; }
1481 memcpy (pstring, princ->data, princ->length);
1482 pstring [princ->length] = '\0';
1485 ret = kadm5_launch_task (handle->context, path, argv, password);
1488 if (pstring != NULL)
1496 ret = krb5_dbe_update_last_pwd_change(handle->context, kdb, now);
1500 /* unlock principal on this KDC */
1501 kdb->fail_auth_count = 0;
1503 /* key data and attributes changed, let the database provider know */
1504 kdb->mask = KADM5_KEY_DATA | KADM5_ATTRIBUTES |
1505 KADM5_FAIL_AUTH_COUNT;
1506 /* | KADM5_CPW_FUNCTION */
1508 ret = k5_kadm5_hook_chpass(handle->context, handle->hook_handles,
1509 KADM5_HOOK_STAGE_PRECOMMIT, principal, keepold,
1510 n_ks_tuple, ks_tuple, password);
1514 if ((ret = kdb_put_entry(handle, kdb, &adb)))
1517 (void) k5_kadm5_hook_chpass(handle->context, handle->hook_handles,
1518 KADM5_HOOK_STAGE_POSTCOMMIT, principal,
1519 keepold, n_ks_tuple, ks_tuple, password);
1522 if (!hist_added && hist.key_data)
1523 free_history_entry(handle->context, &hist);
1524 kdb_free_entry(handle, kdb, &adb);
1525 kdb_free_entry(handle, kdb_save, NULL);
1526 krb5_free_keyblock_contents(handle->context, &hist_keyblock);
1528 if (have_pol && (ret2 = kadm5_free_policy_ent(handle->lhandle, &pol))
1536 kadm5_randkey_principal(void *server_handle,
1537 krb5_principal principal,
1538 krb5_keyblock **keyblocks,
1542 kadm5_randkey_principal_3(server_handle, principal,
1547 kadm5_randkey_principal_3(void *server_handle,
1548 krb5_principal principal,
1549 krb5_boolean keepold,
1550 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1551 krb5_keyblock **keyblocks,
1555 osa_princ_ent_rec adb;
1557 kadm5_policy_ent_rec pol;
1558 int ret, last_pwd, have_pol = 0;
1559 kadm5_server_handle_t handle = server_handle;
1560 krb5_keyblock *act_mkey;
1565 CHECK_HANDLE(server_handle);
1567 /* Use default keysalts if caller did not provide any. */
1568 if (n_ks_tuple == 0) {
1569 ks_tuple = handle->params.keysalts;
1570 n_ks_tuple = handle->params.num_keysalts;
1573 krb5_clear_error_message(handle->context);
1575 if (principal == NULL)
1577 if (krb5_principal_compare(handle->context, principal, hist_princ)) {
1578 /* If changing the history entry, the new entry must have exactly one
1581 return KADM5_PROTECT_PRINCIPAL;
1585 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1588 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
1589 active_mkey_list, NULL, &act_mkey);
1593 ret = krb5_dbe_crk(handle->context, act_mkey, ks_tuple, n_ks_tuple,
1598 kdb->attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1600 ret = krb5_timeofday(handle->context, &now);
1604 if ((adb.aux_attributes & KADM5_POLICY)) {
1605 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1610 ret = krb5_dbe_lookup_last_pwd_change(handle->context, kdb, &last_pwd);
1616 * The spec says this check is overridden if the caller has
1617 * modify privilege. The admin server therefore makes this
1618 * check itself (in chpass_principal_wrapper, misc.c). A
1619 * local caller implicitly has all authorization bits.
1621 if((now - last_pwd) < pol.pw_min_life &&
1622 !(kdb->attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1623 ret = KADM5_PASS_TOOSOON;
1628 if (pol.pw_max_life)
1629 kdb->pw_expiration = now + pol.pw_max_life;
1631 kdb->pw_expiration = 0;
1633 kdb->pw_expiration = 0;
1636 ret = krb5_dbe_update_last_pwd_change(handle->context, kdb, now);
1640 /* unlock principal on this KDC */
1641 kdb->fail_auth_count = 0;
1644 ret = decrypt_key_data(handle->context,
1645 kdb->n_key_data, kdb->key_data,
1651 /* key data changed, let the database provider know */
1652 kdb->mask = KADM5_KEY_DATA | KADM5_FAIL_AUTH_COUNT;
1653 /* | KADM5_RANDKEY_USED */;
1655 ret = k5_kadm5_hook_chpass(handle->context, handle->hook_handles,
1656 KADM5_HOOK_STAGE_PRECOMMIT, principal, keepold,
1657 n_ks_tuple, ks_tuple, NULL);
1660 if ((ret = kdb_put_entry(handle, kdb, &adb)))
1663 (void) k5_kadm5_hook_chpass(handle->context, handle->hook_handles,
1664 KADM5_HOOK_STAGE_POSTCOMMIT, principal,
1665 keepold, n_ks_tuple, ks_tuple, NULL);
1668 kdb_free_entry(handle, kdb, &adb);
1670 kadm5_free_policy_ent(handle->lhandle, &pol);
1676 * kadm5_setv4key_principal:
1678 * Set only ONE key of the principal, removing all others. This key
1679 * must have the DES_CBC_CRC enctype and is entered as having the
1680 * krb4 salttype. This is to enable things like kadmind4 to work.
1683 kadm5_setv4key_principal(void *server_handle,
1684 krb5_principal principal,
1685 krb5_keyblock *keyblock)
1688 osa_princ_ent_rec adb;
1690 kadm5_policy_ent_rec pol;
1691 krb5_keysalt keysalt;
1692 int i, k, kvno, ret, have_pol = 0;
1696 kadm5_server_handle_t handle = server_handle;
1697 krb5_key_data tmp_key_data;
1698 krb5_keyblock *act_mkey;
1700 memset( &tmp_key_data, 0, sizeof(tmp_key_data));
1702 CHECK_HANDLE(server_handle);
1704 krb5_clear_error_message(handle->context);
1706 if (principal == NULL || keyblock == NULL)
1708 if (hist_princ && /* this will be NULL when initializing the databse */
1709 ((krb5_principal_compare(handle->context,
1710 principal, hist_princ)) == TRUE))
1711 return KADM5_PROTECT_PRINCIPAL;
1713 if (keyblock->enctype != ENCTYPE_DES_CBC_CRC)
1714 return KADM5_SETV4KEY_INVAL_ENCTYPE;
1716 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1719 for (kvno = 0, i=0; i<kdb->n_key_data; i++)
1720 if (kdb->key_data[i].key_data_kvno > kvno)
1721 kvno = kdb->key_data[i].key_data_kvno;
1723 if (kdb->key_data != NULL)
1724 cleanup_key_data(handle->context, kdb->n_key_data, kdb->key_data);
1726 kdb->key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, sizeof(krb5_key_data));
1727 if (kdb->key_data == NULL)
1729 memset(kdb->key_data, 0, sizeof(krb5_key_data));
1730 kdb->n_key_data = 1;
1731 keysalt.type = KRB5_KDB_SALTTYPE_V4;
1732 /* XXX data.magic? */
1733 keysalt.data.length = 0;
1734 keysalt.data.data = NULL;
1736 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
1737 active_mkey_list, NULL, &act_mkey);
1741 /* use tmp_key_data as temporary location and reallocate later */
1742 ret = krb5_dbe_encrypt_key_data(handle->context, act_mkey, keyblock,
1743 &keysalt, kvno + 1, &tmp_key_data);
1748 for (k = 0; k < tmp_key_data.key_data_ver; k++) {
1749 kdb->key_data->key_data_type[k] = tmp_key_data.key_data_type[k];
1750 kdb->key_data->key_data_length[k] = tmp_key_data.key_data_length[k];
1751 if (tmp_key_data.key_data_contents[k]) {
1752 kdb->key_data->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]);
1753 if (kdb->key_data->key_data_contents[k] == NULL) {
1754 cleanup_key_data(handle->context, kdb->n_key_data, kdb->key_data);
1755 kdb->key_data = NULL;
1756 kdb->n_key_data = 0;
1760 memcpy (kdb->key_data->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
1762 memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
1763 free (tmp_key_data.key_data_contents[k]);
1764 tmp_key_data.key_data_contents[k] = NULL;
1770 kdb->attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1772 ret = krb5_timeofday(handle->context, &now);
1776 if ((adb.aux_attributes & KADM5_POLICY)) {
1777 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1784 * The spec says this check is overridden if the caller has
1785 * modify privilege. The admin server therefore makes this
1786 * check itself (in chpass_principal_wrapper, misc.c). A
1787 * local caller implicitly has all authorization bits.
1789 if (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1792 if((now - last_pwd) < pol.pw_min_life &&
1793 !(kdb->attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1794 ret = KADM5_PASS_TOOSOON;
1799 if (pol.pw_max_life)
1800 kdb->pw_expiration = now + pol.pw_max_life;
1802 kdb->pw_expiration = 0;
1804 kdb->pw_expiration = 0;
1807 ret = krb5_dbe_update_last_pwd_change(handle->context, kdb, now);
1811 /* unlock principal on this KDC */
1812 kdb->fail_auth_count = 0;
1814 if ((ret = kdb_put_entry(handle, kdb, &adb)))
1819 for (i = 0; i < tmp_key_data.key_data_ver; i++) {
1820 if (tmp_key_data.key_data_contents[i]) {
1821 memset (tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]);
1822 free (tmp_key_data.key_data_contents[i]);
1826 kdb_free_entry(handle, kdb, &adb);
1828 kadm5_free_policy_ent(handle->lhandle, &pol);
1834 kadm5_setkey_principal(void *server_handle,
1835 krb5_principal principal,
1836 krb5_keyblock *keyblocks,
1840 kadm5_setkey_principal_3(server_handle, principal,
1846 kadm5_setkey_principal_3(void *server_handle,
1847 krb5_principal principal,
1848 krb5_boolean keepold,
1849 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1850 krb5_keyblock *keyblocks,
1854 osa_princ_ent_rec adb;
1856 kadm5_policy_ent_rec pol;
1857 krb5_key_data *old_key_data;
1859 int i, j, k, kvno, ret, have_pol = 0;
1863 kadm5_server_handle_t handle = server_handle;
1864 krb5_boolean similar;
1865 krb5_keysalt keysalt;
1866 krb5_key_data tmp_key_data;
1867 krb5_key_data *tptr;
1868 krb5_keyblock *act_mkey;
1870 CHECK_HANDLE(server_handle);
1872 krb5_clear_error_message(handle->context);
1874 if (principal == NULL || keyblocks == NULL)
1876 if (hist_princ && /* this will be NULL when initializing the databse */
1877 ((krb5_principal_compare(handle->context,
1878 principal, hist_princ)) == TRUE))
1879 return KADM5_PROTECT_PRINCIPAL;
1881 for (i = 0; i < n_keys; i++) {
1882 for (j = i+1; j < n_keys; j++) {
1883 if ((ret = krb5_c_enctype_compare(handle->context,
1884 keyblocks[i].enctype,
1885 keyblocks[j].enctype,
1890 if (ks_tuple[i].ks_salttype == ks_tuple[j].ks_salttype)
1891 return KADM5_SETKEY_DUP_ENCTYPES;
1893 return KADM5_SETKEY_DUP_ENCTYPES;
1898 if (n_ks_tuple && n_ks_tuple != n_keys)
1899 return KADM5_SETKEY3_ETYPE_MISMATCH;
1901 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1904 for (kvno = 0, i=0; i<kdb->n_key_data; i++)
1905 if (kdb->key_data[i].key_data_kvno > kvno)
1906 kvno = kdb->key_data[i].key_data_kvno;
1909 old_key_data = kdb->key_data;
1910 n_old_keys = kdb->n_key_data;
1912 if (kdb->key_data != NULL)
1913 cleanup_key_data(handle->context, kdb->n_key_data, kdb->key_data);
1915 old_key_data = NULL;
1918 kdb->key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, (n_keys+n_old_keys)
1919 *sizeof(krb5_key_data));
1920 if (kdb->key_data == NULL) {
1925 memset(kdb->key_data, 0, (n_keys+n_old_keys)*sizeof(krb5_key_data));
1926 kdb->n_key_data = 0;
1928 for (i = 0; i < n_keys; i++) {
1930 keysalt.type = ks_tuple[i].ks_salttype;
1931 keysalt.data.length = 0;
1932 keysalt.data.data = NULL;
1933 if (ks_tuple[i].ks_enctype != keyblocks[i].enctype) {
1934 ret = KADM5_SETKEY3_ETYPE_MISMATCH;
1938 memset (&tmp_key_data, 0, sizeof(tmp_key_data));
1940 ret = krb5_dbe_find_act_mkey(handle->context, master_keylist,
1941 active_mkey_list, NULL, &act_mkey);
1945 ret = krb5_dbe_encrypt_key_data(handle->context, act_mkey,
1947 n_ks_tuple ? &keysalt : NULL, kvno + 1,
1952 tptr = &kdb->key_data[i];
1953 tptr->key_data_ver = tmp_key_data.key_data_ver;
1954 tptr->key_data_kvno = tmp_key_data.key_data_kvno;
1955 for (k = 0; k < tmp_key_data.key_data_ver; k++) {
1956 tptr->key_data_type[k] = tmp_key_data.key_data_type[k];
1957 tptr->key_data_length[k] = tmp_key_data.key_data_length[k];
1958 if (tmp_key_data.key_data_contents[k]) {
1959 tptr->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]);
1960 if (tptr->key_data_contents[k] == NULL) {
1962 for (i1 = k; i1 < tmp_key_data.key_data_ver; i1++) {
1963 if (tmp_key_data.key_data_contents[i1]) {
1964 memset (tmp_key_data.key_data_contents[i1], 0, tmp_key_data.key_data_length[i1]);
1965 free (tmp_key_data.key_data_contents[i1]);
1972 memcpy (tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
1974 memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
1975 free (tmp_key_data.key_data_contents[k]);
1976 tmp_key_data.key_data_contents[k] = NULL;
1982 /* copy old key data if necessary */
1983 for (i = 0; i < n_old_keys; i++) {
1984 kdb->key_data[i+n_keys] = old_key_data[i];
1985 memset(&old_key_data[i], 0, sizeof (krb5_key_data));
1990 krb5_db_free(handle->context, old_key_data);
1992 /* assert(kdb->n_key_data == n_keys + n_old_keys) */
1993 kdb->attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1995 if ((ret = krb5_timeofday(handle->context, &now)))
1998 if ((adb.aux_attributes & KADM5_POLICY)) {
1999 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
2006 * The spec says this check is overridden if the caller has
2007 * modify privilege. The admin server therefore makes this
2008 * check itself (in chpass_principal_wrapper, misc.c). A
2009 * local caller implicitly has all authorization bits.
2011 if (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
2014 if((now - last_pwd) < pol.pw_min_life &&
2015 !(kdb->attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
2016 ret = KADM5_PASS_TOOSOON;
2021 if (pol.pw_max_life)
2022 kdb->pw_expiration = now + pol.pw_max_life;
2024 kdb->pw_expiration = 0;
2026 kdb->pw_expiration = 0;
2029 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, kdb, now)))
2032 /* unlock principal on this KDC */
2033 kdb->fail_auth_count = 0;
2035 if ((ret = kdb_put_entry(handle, kdb, &adb)))
2040 kdb_free_entry(handle, kdb, &adb);
2042 kadm5_free_policy_ent(handle->lhandle, &pol);
2048 * Return the list of keys like kadm5_randkey_principal,
2049 * but don't modify the principal.
2052 kadm5_get_principal_keys(void *server_handle /* IN */,
2053 krb5_principal principal /* IN */,
2054 krb5_keyblock **keyblocks /* OUT */,
2055 int *n_keys /* OUT */)
2058 osa_princ_ent_rec adb;
2060 kadm5_server_handle_t handle = server_handle;
2065 CHECK_HANDLE(server_handle);
2067 if (principal == NULL)
2070 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
2074 ret = decrypt_key_data(handle->context,
2075 kdb->n_key_data, kdb->key_data,
2083 kdb_free_entry(handle, kdb, &adb);
2090 * Allocate an array of n_key_data krb5_keyblocks, fill in each
2091 * element with the results of decrypting the nth key in key_data,
2092 * and if n_keys is not NULL fill it in with the
2093 * number of keys decrypted.
2095 static int decrypt_key_data(krb5_context context,
2096 int n_key_data, krb5_key_data *key_data,
2097 krb5_keyblock **keyblocks, int *n_keys)
2099 krb5_keyblock *keys;
2102 keys = (krb5_keyblock *) malloc(n_key_data*sizeof(krb5_keyblock));
2105 memset(keys, 0, n_key_data*sizeof(krb5_keyblock));
2107 for (i = 0; i < n_key_data; i++) {
2108 ret = krb5_dbe_decrypt_key_data(context, NULL, &key_data[i], &keys[i],
2111 for (; i >= 0; i--) {
2112 if (keys[i].contents) {
2113 memset (keys[i].contents, 0, keys[i].length);
2114 free( keys[i].contents );
2118 memset(keys, 0, n_key_data*sizeof(krb5_keyblock));
2126 *n_keys = n_key_data;
2132 * Function: kadm5_decrypt_key
2134 * Purpose: Retrieves and decrypts a principal key.
2138 * server_handle (r) kadm5 handle
2139 * entry (r) principal retrieved with kadm5_get_principal
2140 * ktype (r) enctype to search for, or -1 to ignore
2141 * stype (r) salt type to search for, or -1 to ignore
2142 * kvno (r) kvno to search for, -1 for max, 0 for max
2143 * only if it also matches ktype and stype
2144 * keyblock (w) keyblock to fill in
2145 * keysalt (w) keysalt to fill in, or NULL
2146 * kvnop (w) kvno to fill in, or NULL
2148 * Effects: Searches the key_data array of entry, which must have been
2149 * retrived with kadm5_get_principal with the KADM5_KEY_DATA mask, to
2150 * find a key with a specified enctype, salt type, and kvno in a
2151 * principal entry. If not found, return ENOENT. Otherwise, decrypt
2152 * it with the master key, and return the key in keyblock, the salt
2153 * in salttype, and the key version number in kvno.
2155 * If ktype or stype is -1, it is ignored for the search. If kvno is
2156 * -1, ktype and stype are ignored and the key with the max kvno is
2157 * returned. If kvno is 0, only the key with the max kvno is returned
2158 * and only if it matches the ktype and stype; otherwise, ENOENT is
2161 kadm5_ret_t kadm5_decrypt_key(void *server_handle,
2162 kadm5_principal_ent_t entry, krb5_int32
2163 ktype, krb5_int32 stype, krb5_int32
2164 kvno, krb5_keyblock *keyblock,
2165 krb5_keysalt *keysalt, int *kvnop)
2167 kadm5_server_handle_t handle = server_handle;
2168 krb5_db_entry dbent;
2169 krb5_key_data *key_data;
2170 krb5_keyblock *mkey_ptr;
2173 CHECK_HANDLE(server_handle);
2175 if (entry->n_key_data == 0 || entry->key_data == NULL)
2178 /* find_enctype only uses these two fields */
2179 dbent.n_key_data = entry->n_key_data;
2180 dbent.key_data = entry->key_data;
2181 if ((ret = krb5_dbe_find_enctype(handle->context, &dbent, ktype,
2182 stype, kvno, &key_data)))
2185 /* find_mkey only uses this field */
2186 dbent.tl_data = entry->tl_data;
2187 if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist, &dbent,
2189 krb5_keylist_node *tmp_mkey_list;
2190 /* try refreshing master key list */
2191 /* XXX it would nice if we had the mkvno here for optimization */
2192 if (krb5_db_fetch_mkey_list(handle->context, master_princ,
2193 &master_keyblock, 0, &tmp_mkey_list) == 0) {
2194 krb5_dbe_free_key_list(handle->context, master_keylist);
2195 master_keylist = tmp_mkey_list;
2196 if ((ret = krb5_dbe_find_mkey(handle->context, master_keylist,
2197 &dbent, &mkey_ptr))) {
2205 if ((ret = krb5_dbe_decrypt_key_data(handle->context, NULL, key_data,
2206 keyblock, keysalt)))
2210 * Coerce the enctype of the output keyblock in case we got an
2211 * inexact match on the enctype; this behavior will go away when
2212 * the key storage architecture gets redesigned for 1.3.
2215 keyblock->enctype = ktype;
2218 *kvnop = key_data->key_data_kvno;
2224 kadm5_purgekeys(void *server_handle,
2225 krb5_principal principal,
2228 kadm5_server_handle_t handle = server_handle;
2231 osa_princ_ent_rec adb;
2232 krb5_key_data *old_keydata;
2236 CHECK_HANDLE(server_handle);
2238 if (principal == NULL)
2241 ret = kdb_get_entry(handle, principal, &kdb, &adb);
2245 if (keepkvno <= 0) {
2246 keepkvno = krb5_db_get_key_data_kvno(handle->context, kdb->n_key_data,
2250 old_keydata = kdb->key_data;
2251 n_old_keydata = kdb->n_key_data;
2252 kdb->n_key_data = 0;
2253 kdb->key_data = krb5_db_alloc(handle->context, NULL,
2254 n_old_keydata * sizeof(krb5_key_data));
2255 if (kdb->key_data == NULL) {
2259 memset(kdb->key_data, 0, n_old_keydata * sizeof(krb5_key_data));
2260 for (i = 0, j = 0; i < n_old_keydata; i++) {
2261 if (old_keydata[i].key_data_kvno < keepkvno)
2264 /* Alias the key_data_contents pointers; we null them out in the
2265 * source array immediately after. */
2266 kdb->key_data[j] = old_keydata[i];
2267 for (k = 0; k < old_keydata[i].key_data_ver; k++) {
2268 old_keydata[i].key_data_contents[k] = NULL;
2272 kdb->n_key_data = j;
2273 cleanup_key_data(handle->context, n_old_keydata, old_keydata);
2275 kdb->mask = KADM5_KEY_DATA;
2276 ret = kdb_put_entry(handle, kdb, &adb);
2281 kdb_free_entry(handle, kdb, &adb);