2 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
7 #if !defined(lint) && !defined(__CODECENTER__)
8 static char *rcsid = "$Header$";
11 #include <sys/types.h>
13 #include <kadm5/admin.h>
18 #include "server_internal.h"
21 #ifdef USE_PASSWORD_SERVER
25 extern krb5_principal master_princ;
26 extern krb5_principal hist_princ;
27 extern krb5_keyblock master_keyblock;
28 extern krb5_keyblock hist_key;
29 extern krb5_db_entry master_db;
30 extern krb5_db_entry hist_db;
31 extern krb5_kvno hist_kvno;
33 static int decrypt_key_data(krb5_context context,
34 int n_key_data, krb5_key_data *key_data,
35 krb5_keyblock **keyblocks, int *n_keys);
37 static krb5_error_code
38 kadm5_copy_principal(krb5_context context, krb5_const_principal inprinc, krb5_principal *outprinc)
40 register krb5_principal tempprinc;
41 register int i, nelems;
43 tempprinc = (krb5_principal)krb5_db_alloc(context, NULL, sizeof(krb5_principal_data));
48 memcpy(tempprinc, inprinc, sizeof(krb5_principal_data));
50 nelems = (int) krb5_princ_size(context, inprinc);
51 tempprinc->data = krb5_db_alloc(context, NULL, nelems * sizeof(krb5_data));
53 if (tempprinc->data == 0) {
54 krb5_db_free(context, (char *)tempprinc);
58 for (i = 0; i < nelems; i++) {
59 unsigned int len = krb5_princ_component(context, inprinc, i)->length;
60 krb5_princ_component(context, tempprinc, i)->length = len;
61 if (((krb5_princ_component(context, tempprinc, i)->data =
62 krb5_db_alloc(context, NULL, len)) == 0) && len) {
64 krb5_db_free(context, krb5_princ_component(context, tempprinc, i)->data);
65 krb5_db_free (context, tempprinc->data);
66 krb5_db_free (context, tempprinc);
70 memcpy(krb5_princ_component(context, tempprinc, i)->data,
71 krb5_princ_component(context, inprinc, i)->data, len);
74 tempprinc->realm.data =
75 krb5_db_alloc(context, NULL, tempprinc->realm.length = inprinc->realm.length);
76 if (!tempprinc->realm.data && tempprinc->realm.length) {
77 for (i = 0; i < nelems; i++)
78 krb5_db_free(context, krb5_princ_component(context, tempprinc, i)->data);
79 krb5_db_free(context, tempprinc->data);
80 krb5_db_free(context, tempprinc);
83 if (tempprinc->realm.length)
84 memcpy(tempprinc->realm.data, inprinc->realm.data,
85 inprinc->realm.length);
87 *outprinc = tempprinc;
92 kadm5_free_principal(krb5_context context, krb5_principal val)
94 register krb5_int32 i;
100 i = krb5_princ_size(context, val);
102 krb5_db_free(context, krb5_princ_component(context, val, i)->data);
103 krb5_db_free(context, val->data);
106 krb5_db_free(context, val->realm.data);
107 krb5_db_free(context, val);
111 * XXX Functions that ought to be in libkrb5.a, but aren't.
113 kadm5_ret_t krb5_copy_key_data_contents(context, from, to)
114 krb5_context context;
115 krb5_key_data *from, *to;
121 idx = (from->key_data_ver == 1 ? 1 : 2);
123 for (i = 0; i < idx; i++) {
124 if ( from->key_data_length[i] ) {
125 to->key_data_contents[i] = malloc(from->key_data_length[i]);
126 if (to->key_data_contents[i] == NULL) {
127 for (i = 0; i < idx; i++) {
128 if (to->key_data_contents[i]) {
129 memset(to->key_data_contents[i], 0,
130 to->key_data_length[i]);
131 free(to->key_data_contents[i]);
136 memcpy(to->key_data_contents[i], from->key_data_contents[i],
137 from->key_data_length[i]);
143 static krb5_tl_data *dup_tl_data(krb5_tl_data *tl)
147 n = (krb5_tl_data *) malloc(sizeof(krb5_tl_data));
150 n->tl_data_contents = malloc(tl->tl_data_length);
151 if (n->tl_data_contents == NULL) {
155 memcpy(n->tl_data_contents, tl->tl_data_contents, tl->tl_data_length);
156 n->tl_data_type = tl->tl_data_type;
157 n->tl_data_length = tl->tl_data_length;
158 n->tl_data_next = NULL;
162 /* This is in lib/kdb/kdb_cpw.c, but is static */
163 static void cleanup_key_data(context, count, data)
164 krb5_context context;
166 krb5_key_data * data;
170 for (i = 0; i < count; i++)
171 for (j = 0; j < data[i].key_data_ver; j++)
172 if (data[i].key_data_length[j])
173 krb5_db_free(context, data[i].key_data_contents[j]);
174 krb5_db_free(context, data);
178 kadm5_create_principal(void *server_handle,
179 kadm5_principal_ent_t entry, long mask,
183 kadm5_create_principal_3(server_handle, entry, mask,
187 kadm5_create_principal_3(void *server_handle,
188 kadm5_principal_ent_t entry, long mask,
189 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
193 osa_princ_ent_rec adb;
194 kadm5_policy_ent_rec polent;
196 krb5_tl_data *tl_data_orig, *tl_data_tail;
198 kadm5_server_handle_t handle = server_handle;
200 CHECK_HANDLE(server_handle);
205 * Argument sanity checking, and opening up the DB
207 if(!(mask & KADM5_PRINCIPAL) || (mask & KADM5_MOD_NAME) ||
208 (mask & KADM5_MOD_TIME) || (mask & KADM5_LAST_PWD_CHANGE) ||
209 (mask & KADM5_MKVNO) || (mask & KADM5_POLICY_CLR) ||
210 (mask & KADM5_AUX_ATTRIBUTES) || (mask & KADM5_KEY_DATA) ||
211 (mask & KADM5_LAST_SUCCESS) || (mask & KADM5_LAST_FAILED) ||
212 (mask & KADM5_FAIL_AUTH_COUNT))
213 return KADM5_BAD_MASK;
214 if((mask & ~ALL_PRINC_MASK))
215 return KADM5_BAD_MASK;
216 if (entry == (kadm5_principal_ent_t) NULL || password == NULL)
220 * Check to see if the principal exists
222 ret = kdb_get_entry(handle, entry->principal, &kdb, &adb);
225 case KADM5_UNK_PRINC:
228 kdb_free_entry(handle, &kdb, &adb);
234 memset(&kdb, 0, sizeof(krb5_db_entry));
235 memset(&adb, 0, sizeof(osa_princ_ent_rec));
238 * If a policy was specified, load it.
239 * If we can not find the one specified return an error
241 if ((mask & KADM5_POLICY)) {
242 if ((ret = kadm5_get_policy(handle->lhandle, entry->policy,
243 &polent)) != KADM5_OK) {
245 return KADM5_BAD_POLICY;
250 if ((ret = passwd_check(handle, password, (mask & KADM5_POLICY),
251 &polent, entry->principal))) {
252 if (mask & KADM5_POLICY)
253 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
257 * Start populating the various DB fields, using the
258 * "defaults" for fields that were not specified by the
261 if ((ret = krb5_timeofday(handle->context, &now))) {
262 if (mask & KADM5_POLICY)
263 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
267 kdb.magic = KRB5_KDB_MAGIC_NUMBER;
268 kdb.len = KRB5_KDB_V1_BASE_LENGTH; /* gag me with a chainsaw */
270 if ((mask & KADM5_ATTRIBUTES))
271 kdb.attributes = entry->attributes;
273 kdb.attributes = handle->params.flags;
275 if ((mask & KADM5_MAX_LIFE))
276 kdb.max_life = entry->max_life;
278 kdb.max_life = handle->params.max_life;
280 if (mask & KADM5_MAX_RLIFE)
281 kdb.max_renewable_life = entry->max_renewable_life;
283 kdb.max_renewable_life = handle->params.max_rlife;
285 if ((mask & KADM5_PRINC_EXPIRE_TIME))
286 kdb.expiration = entry->princ_expire_time;
288 kdb.expiration = handle->params.expiration;
290 kdb.pw_expiration = 0;
291 if ((mask & KADM5_POLICY)) {
292 if(polent.pw_max_life)
293 kdb.pw_expiration = now + polent.pw_max_life;
295 kdb.pw_expiration = 0;
297 if ((mask & KADM5_PW_EXPIRATION))
298 kdb.pw_expiration = entry->pw_expiration;
300 kdb.last_success = 0;
302 kdb.fail_auth_count = 0;
304 /* this is kind of gross, but in order to free the tl data, I need
305 to free the entire kdb entry, and that will try to free the
308 if ((ret = kadm5_copy_principal(handle->context,
309 entry->principal, &(kdb.princ)))) {
310 if (mask & KADM5_POLICY)
311 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
315 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now))) {
316 krb5_db_free_principal(handle->context, &kdb, 1);
317 if (mask & KADM5_POLICY)
318 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
322 if (mask & KADM5_TL_DATA) {
323 /* splice entry->tl_data onto the front of kdb.tl_data */
324 tl_data_orig = kdb.tl_data;
325 for (tl_data_tail = entry->tl_data; tl_data_tail;
326 tl_data_tail = tl_data_tail->tl_data_next)
328 ret = krb5_dbe_update_tl_data(handle->context, &kdb, tl_data_tail);
331 krb5_db_free_principal(handle->context, &kdb, 1);
332 if (mask & KADM5_POLICY)
333 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
339 /* initialize the keys */
341 if ((ret = krb5_dbe_cpw(handle->context, &master_keyblock,
342 n_ks_tuple?ks_tuple:handle->params.keysalts,
343 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
345 (mask & KADM5_KVNO)?entry->kvno:1,
347 krb5_db_free_principal(handle->context, &kdb, 1);
348 if (mask & KADM5_POLICY)
349 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
353 /* populate the admin-server-specific fields. In the OV server,
354 this used to be in a separate database. Since there's already
355 marshalling code for the admin fields, to keep things simple,
356 I'm going to keep it, and make all the admin stuff occupy a
357 single tl_data record, */
359 adb.admin_history_kvno = hist_kvno;
360 if ((mask & KADM5_POLICY)) {
361 adb.aux_attributes = KADM5_POLICY;
363 /* this does *not* need to be strdup'ed, because adb is xdr */
364 /* encoded in osa_adb_create_princ, and not ever freed */
366 adb.policy = entry->policy;
369 /* increment the policy ref count, if any */
371 if ((mask & KADM5_POLICY)) {
372 polent.policy_refcnt++;
373 if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent,
376 krb5_db_free_principal(handle->context, &kdb, 1);
377 if (mask & KADM5_POLICY)
378 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
383 /* store the new db entry */
384 ret = kdb_put_entry(handle, &kdb, &adb);
386 krb5_db_free_principal(handle->context, &kdb, 1);
389 if ((mask & KADM5_POLICY)) {
390 /* decrement the policy ref count */
392 polent.policy_refcnt--;
394 * if this fails, there's nothing we can do anyway. the
395 * policy refcount wil be too high.
397 (void) kadm5_modify_policy_internal(handle->lhandle, &polent,
401 if (mask & KADM5_POLICY)
402 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
406 if (mask & KADM5_POLICY)
407 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
414 kadm5_delete_principal(void *server_handle, krb5_principal principal)
417 kadm5_policy_ent_rec polent;
419 osa_princ_ent_rec adb;
420 kadm5_server_handle_t handle = server_handle;
422 CHECK_HANDLE(server_handle);
426 if (principal == NULL)
429 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
432 if ((adb.aux_attributes & KADM5_POLICY)) {
433 if ((ret = kadm5_get_policy(handle->lhandle,
434 adb.policy, &polent))
436 polent.policy_refcnt--;
437 if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent,
440 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
441 kdb_free_entry(handle, &kdb, &adb);
445 if ((ret = kadm5_free_policy_ent(handle->lhandle, &polent))) {
446 kdb_free_entry(handle, &kdb, &adb);
451 ret = kdb_delete_entry(handle, principal);
453 kdb_free_entry(handle, &kdb, &adb);
459 kadm5_modify_principal(void *server_handle,
460 kadm5_principal_ent_t entry, long mask)
463 kadm5_policy_ent_rec npol, opol;
464 int have_npol = 0, have_opol = 0;
466 krb5_tl_data *tl_data_orig;
467 osa_princ_ent_rec adb;
468 kadm5_server_handle_t handle = server_handle;
470 CHECK_HANDLE(server_handle);
474 if((mask & KADM5_PRINCIPAL) || (mask & KADM5_LAST_PWD_CHANGE) ||
475 (mask & KADM5_MOD_TIME) || (mask & KADM5_MOD_NAME) ||
476 (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) ||
477 (mask & KADM5_KEY_DATA) || (mask & KADM5_LAST_SUCCESS) ||
478 (mask & KADM5_LAST_FAILED))
479 return KADM5_BAD_MASK;
480 if((mask & ~ALL_PRINC_MASK))
481 return KADM5_BAD_MASK;
482 if((mask & KADM5_POLICY) && (mask & KADM5_POLICY_CLR))
483 return KADM5_BAD_MASK;
484 if(entry == (kadm5_principal_ent_t) NULL)
486 if (mask & KADM5_TL_DATA) {
487 tl_data_orig = entry->tl_data;
488 while (tl_data_orig) {
489 if (tl_data_orig->tl_data_type < 256)
490 return KADM5_BAD_TL_TYPE;
491 tl_data_orig = tl_data_orig->tl_data_next;
495 ret = kdb_get_entry(handle, entry->principal, &kdb, &adb);
500 * This is pretty much the same as create ...
503 if ((mask & KADM5_POLICY)) {
504 /* get the new policy */
505 ret = kadm5_get_policy(handle->lhandle, entry->policy, &npol);
509 ret = KADM5_BAD_POLICY;
511 case KADM5_UNK_POLICY:
512 case KADM5_BAD_POLICY:
513 ret = KADM5_UNK_POLICY;
520 /* if we already have a policy, get it to decrement the refcnt */
521 if(adb.aux_attributes & KADM5_POLICY) {
522 /* ... but not if the old and new are the same */
523 if(strcmp(adb.policy, entry->policy)) {
524 ret = kadm5_get_policy(handle->lhandle,
528 case KADM5_BAD_POLICY:
529 case KADM5_UNK_POLICY:
533 opol.policy_refcnt--;
539 npol.policy_refcnt++;
541 } else npol.policy_refcnt++;
543 /* set us up to use the new policy */
544 adb.aux_attributes |= KADM5_POLICY;
547 adb.policy = strdup(entry->policy);
549 /* set pw_max_life based on new policy */
550 if (npol.pw_max_life) {
551 ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb,
552 &(kdb.pw_expiration));
555 kdb.pw_expiration += npol.pw_max_life;
557 kdb.pw_expiration = 0;
561 if ((mask & KADM5_POLICY_CLR) &&
562 (adb.aux_attributes & KADM5_POLICY)) {
563 ret = kadm5_get_policy(handle->lhandle, adb.policy, &opol);
566 case KADM5_BAD_POLICY:
567 case KADM5_UNK_POLICY:
576 adb.aux_attributes &= ~KADM5_POLICY;
577 kdb.pw_expiration = 0;
578 opol.policy_refcnt--;
586 if (((mask & KADM5_POLICY) || (mask & KADM5_POLICY_CLR)) &&
589 kadm5_modify_policy_internal(handle->lhandle, &opol,
590 KADM5_REF_COUNT))) ||
593 kadm5_modify_policy_internal(handle->lhandle, &npol,
597 if ((mask & KADM5_ATTRIBUTES))
598 kdb.attributes = entry->attributes;
599 if ((mask & KADM5_MAX_LIFE))
600 kdb.max_life = entry->max_life;
601 if ((mask & KADM5_PRINC_EXPIRE_TIME))
602 kdb.expiration = entry->princ_expire_time;
603 if (mask & KADM5_PW_EXPIRATION)
604 kdb.pw_expiration = entry->pw_expiration;
605 if (mask & KADM5_MAX_RLIFE)
606 kdb.max_renewable_life = entry->max_renewable_life;
607 if (mask & KADM5_FAIL_AUTH_COUNT)
608 kdb.fail_auth_count = entry->fail_auth_count;
610 if((mask & KADM5_KVNO)) {
611 for (i = 0; i < kdb.n_key_data; i++)
612 kdb.key_data[i].key_data_kvno = entry->kvno;
615 if (mask & KADM5_TL_DATA) {
618 /* may have to change the version number of the API. Updates the list with the given tl_data rather than over-writting */
620 for (tl = entry->tl_data; tl;
621 tl = tl->tl_data_next)
623 ret = krb5_dbe_update_tl_data(handle->context, &kdb, tl);
631 ret = kdb_put_entry(handle, &kdb, &adb);
637 ret2 = kadm5_free_policy_ent(handle->lhandle, &opol);
638 ret = ret ? ret : ret2;
641 ret2 = kadm5_free_policy_ent(handle->lhandle, &npol);
642 ret = ret ? ret : ret2;
644 kdb_free_entry(handle, &kdb, &adb);
649 kadm5_rename_principal(void *server_handle,
650 krb5_principal source, krb5_principal target)
653 osa_princ_ent_rec adb;
655 kadm5_server_handle_t handle = server_handle;
657 CHECK_HANDLE(server_handle);
661 if (source == NULL || target == NULL)
664 if ((ret = kdb_get_entry(handle, target, &kdb, &adb)) == 0) {
665 kdb_free_entry(handle, &kdb, &adb);
669 if ((ret = kdb_get_entry(handle, source, &kdb, &adb)))
672 /* this is kinda gross, but unavoidable */
674 for (i=0; i<kdb.n_key_data; i++) {
675 if ((kdb.key_data[i].key_data_ver == 1) ||
676 (kdb.key_data[i].key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL)) {
677 ret = KADM5_NO_RENAME_SALT;
682 kadm5_free_principal(handle->context, kdb.princ);
683 ret = kadm5_copy_principal(handle->context, target, &kdb.princ);
685 kdb.princ = NULL; /* so freeing the dbe doesn't lose */
689 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
692 ret = kdb_delete_entry(handle, source);
695 kdb_free_entry(handle, &kdb, &adb);
700 kadm5_get_principal(void *server_handle, krb5_principal principal,
701 kadm5_principal_ent_t entry,
705 osa_princ_ent_rec adb;
706 krb5_error_code ret = 0;
709 kadm5_server_handle_t handle = server_handle;
710 kadm5_principal_ent_rec entry_local, *entry_orig;
712 CHECK_HANDLE(server_handle);
717 * In version 1, all the defined fields are always returned.
718 * entry is a pointer to a kadm5_principal_ent_t_v1 that should be
719 * filled with allocated memory.
721 if (handle->api_version == KADM5_API_VERSION_1) {
722 mask = KADM5_PRINCIPAL_NORMAL_MASK;
724 entry = &entry_local;
729 memset((char *) entry, 0, sizeof(*entry));
731 if (principal == NULL)
734 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
737 if ((mask & KADM5_POLICY) &&
738 adb.policy && (adb.aux_attributes & KADM5_POLICY)) {
739 if ((entry->policy = (char *) malloc(strlen(adb.policy) + 1)) == NULL) {
743 strcpy(entry->policy, adb.policy);
746 if (mask & KADM5_AUX_ATTRIBUTES)
747 entry->aux_attributes = adb.aux_attributes;
749 if ((mask & KADM5_PRINCIPAL) &&
750 (ret = krb5_copy_principal(handle->context, principal,
751 &entry->principal))) {
755 if (mask & KADM5_PRINC_EXPIRE_TIME)
756 entry->princ_expire_time = kdb.expiration;
758 if ((mask & KADM5_LAST_PWD_CHANGE) &&
759 (ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb,
760 &(entry->last_pwd_change)))) {
764 if (mask & KADM5_PW_EXPIRATION)
765 entry->pw_expiration = kdb.pw_expiration;
766 if (mask & KADM5_MAX_LIFE)
767 entry->max_life = kdb.max_life;
769 /* this is a little non-sensical because the function returns two */
770 /* values that must be checked separately against the mask */
771 if ((mask & KADM5_MOD_NAME) || (mask & KADM5_MOD_TIME)) {
772 ret = krb5_dbe_lookup_mod_princ_data(handle->context, &kdb,
779 if (! (mask & KADM5_MOD_TIME))
781 if (! (mask & KADM5_MOD_NAME)) {
782 krb5_free_principal(handle->context, entry->principal);
783 entry->principal = NULL;
787 if (mask & KADM5_ATTRIBUTES)
788 entry->attributes = kdb.attributes;
790 if (mask & KADM5_KVNO)
791 for (entry->kvno = 0, i=0; i<kdb.n_key_data; i++)
792 if (kdb.key_data[i].key_data_kvno > entry->kvno)
793 entry->kvno = kdb.key_data[i].key_data_kvno;
795 if (handle->api_version == KADM5_API_VERSION_2)
798 /* XXX I'll be damned if I know how to deal with this one --marc */
803 * The new fields that only exist in version 2 start here
805 if (handle->api_version == KADM5_API_VERSION_2) {
806 if (mask & KADM5_MAX_RLIFE)
807 entry->max_renewable_life = kdb.max_renewable_life;
808 if (mask & KADM5_LAST_SUCCESS)
809 entry->last_success = kdb.last_success;
810 if (mask & KADM5_LAST_FAILED)
811 entry->last_failed = kdb.last_failed;
812 if (mask & KADM5_FAIL_AUTH_COUNT)
813 entry->fail_auth_count = kdb.fail_auth_count;
814 if (mask & KADM5_TL_DATA) {
815 krb5_tl_data *tl, *tl2;
817 entry->tl_data = NULL;
821 if (tl->tl_data_type > 255) {
822 if ((tl2 = dup_tl_data(tl)) == NULL) {
826 tl2->tl_data_next = entry->tl_data;
827 entry->tl_data = tl2;
831 tl = tl->tl_data_next;
834 if (mask & KADM5_KEY_DATA) {
835 entry->n_key_data = kdb.n_key_data;
836 if(entry->n_key_data) {
837 entry->key_data = (krb5_key_data *)
838 malloc(entry->n_key_data*sizeof(krb5_key_data));
839 if (entry->key_data == NULL) {
844 entry->key_data = NULL;
846 for (i = 0; i < entry->n_key_data; i++)
847 ret = krb5_copy_key_data_contents(handle->context,
849 &entry->key_data[i]);
856 * If KADM5_API_VERSION_1, we return an allocated structure, and
857 * we need to convert the new structure back into the format the
858 * caller is expecting.
860 if (handle->api_version == KADM5_API_VERSION_1) {
861 kadm5_principal_ent_t_v1 newv1;
863 newv1 = ((kadm5_principal_ent_t_v1) calloc(1, sizeof(*newv1)));
869 newv1->principal = entry->principal;
870 newv1->princ_expire_time = entry->princ_expire_time;
871 newv1->last_pwd_change = entry->last_pwd_change;
872 newv1->pw_expiration = entry->pw_expiration;
873 newv1->max_life = entry->max_life;
874 newv1->mod_name = entry->mod_name;
875 newv1->mod_date = entry->mod_date;
876 newv1->attributes = entry->attributes;
877 newv1->kvno = entry->kvno;
878 newv1->mkvno = entry->mkvno;
879 newv1->policy = entry->policy;
880 newv1->aux_attributes = entry->aux_attributes;
882 *((kadm5_principal_ent_t_v1 *) entry_orig) = newv1;
888 if (ret && entry->principal)
889 krb5_free_principal(handle->context, entry->principal);
890 kdb_free_entry(handle, &kdb, &adb);
896 * Function: check_pw_reuse
898 * Purpose: Check if a key appears in a list of keys, in order to
899 * enforce password history.
903 * context (r) the krb5 context
904 * hist_keyblock (r) the key that hist_key_data is
906 * n_new_key_data (r) length of new_key_data
907 * new_key_data (r) keys to check against
908 * pw_hist_data, encrypted in hist_keyblock
909 * n_pw_hist_data (r) length of pw_hist_data
910 * pw_hist_data (r) passwords to check new_key_data against
913 * For each new_key in new_key_data:
914 * decrypt new_key with the master_keyblock
915 * for each password in pw_hist_data:
916 * for each hist_key in password:
917 * decrypt hist_key with hist_keyblock
918 * compare the new_key and hist_key
920 * Returns krb5 errors, KADM5_PASS_RESUSE if a key in
921 * new_key_data is the same as a key in pw_hist_data, or 0.
924 check_pw_reuse(krb5_context context,
925 krb5_keyblock *hist_keyblock,
926 int n_new_key_data, krb5_key_data *new_key_data,
927 unsigned int n_pw_hist_data, osa_pw_hist_ent *pw_hist_data)
930 krb5_keyblock newkey, histkey;
933 for (x = 0; x < n_new_key_data; x++) {
934 ret = krb5_dbekd_decrypt_key_data(context,
940 for (y = 0; y < n_pw_hist_data; y++) {
941 for (z = 0; z < pw_hist_data[y].n_key_data; z++) {
942 ret = krb5_dbekd_decrypt_key_data(context,
944 &pw_hist_data[y].key_data[z],
949 if ((newkey.length == histkey.length) &&
950 (newkey.enctype == histkey.enctype) &&
951 (memcmp(newkey.contents, histkey.contents,
952 histkey.length) == 0)) {
953 krb5_free_keyblock_contents(context, &histkey);
954 krb5_free_keyblock_contents(context, &newkey);
956 return(KADM5_PASS_REUSE);
958 krb5_free_keyblock_contents(context, &histkey);
961 krb5_free_keyblock_contents(context, &newkey);
968 * Function: create_history_entry
970 * Purpose: Creates a password history entry from an array of
975 * context (r) krb5_context to use
976 * n_key_data (r) number of elements in key_data
977 * key_data (r) keys to add to the history entry
978 * hist (w) history entry to fill in
982 * hist->key_data is allocated to store n_key_data key_datas. Each
983 * element of key_data is decrypted with master_keyblock, re-encrypted
984 * in hist_key, and added to hist->key_data. hist->n_key_data is
988 int create_history_entry(krb5_context context, int n_key_data,
989 krb5_key_data *key_data, osa_pw_hist_ent *hist)
995 hist->key_data = (krb5_key_data*)malloc(n_key_data*sizeof(krb5_key_data));
996 if (hist->key_data == NULL)
998 memset(hist->key_data, 0, n_key_data*sizeof(krb5_key_data));
1000 for (i = 0; i < n_key_data; i++) {
1001 ret = krb5_dbekd_decrypt_key_data(context,
1008 ret = krb5_dbekd_encrypt_key_data(context, &hist_key,
1010 key_data[i].key_data_kvno,
1011 &hist->key_data[i]);
1015 krb5_free_keyblock_contents(context, &key);
1016 /* krb5_free_keysalt(context, &salt); */
1019 hist->n_key_data = n_key_data;
1024 void free_history_entry(krb5_context context, osa_pw_hist_ent *hist)
1028 for (i = 0; i < hist->n_key_data; i++)
1029 krb5_free_key_data_contents(context, &hist->key_data[i]);
1030 free(hist->key_data);
1034 * Function: add_to_history
1036 * Purpose: Adds a password to a principal's password history.
1040 * context (r) krb5_context to use
1041 * adb (r/w) admin principal entry to add keys to
1042 * pol (r) adb's policy
1043 * pw (r) keys for the password to add to adb's key history
1047 * add_to_history adds a single password to adb's password history.
1048 * pw contains n_key_data keys in its key_data, in storage should be
1049 * allocated but not freed by the caller (XXX blech!).
1051 * This function maintains adb->old_keys as a circular queue. It
1052 * starts empty, and grows each time this function is called until it
1053 * is pol->pw_history_num items long. adb->old_key_len holds the
1054 * number of allocated entries in the array, and must therefore be [0,
1055 * pol->pw_history_num). adb->old_key_next is the index into the
1056 * array where the next element should be written, and must be [0,
1057 * adb->old_key_len).
1059 static kadm5_ret_t add_to_history(krb5_context context,
1060 osa_princ_ent_t adb,
1061 kadm5_policy_ent_t pol,
1062 osa_pw_hist_ent *pw)
1064 osa_pw_hist_ent *histp;
1066 unsigned int i, knext, nkeys;
1068 nhist = pol->pw_history_num;
1069 /* A history of 1 means just check the current password */
1073 nkeys = adb->old_key_len;
1074 knext = adb->old_key_next;
1075 /* resize the adb->old_keys array if necessary */
1076 if (nkeys + 1 < nhist) {
1077 if (adb->old_keys == NULL) {
1078 adb->old_keys = (osa_pw_hist_ent *)
1079 malloc((nkeys + 1) * sizeof (osa_pw_hist_ent));
1081 adb->old_keys = (osa_pw_hist_ent *)
1082 realloc(adb->old_keys,
1083 (nkeys + 1) * sizeof (osa_pw_hist_ent));
1085 if (adb->old_keys == NULL)
1088 memset(&adb->old_keys[nkeys], 0, sizeof(osa_pw_hist_ent));
1089 nkeys = ++adb->old_key_len;
1091 * To avoid losing old keys, shift forward each entry after
1094 for (i = nkeys - 1; i > knext; i--) {
1095 adb->old_keys[i] = adb->old_keys[i - 1];
1097 memset(&adb->old_keys[knext], 0, sizeof(osa_pw_hist_ent));
1098 } else if (nkeys + 1 > nhist) {
1100 * The policy must have changed! Shrink the array.
1101 * Can't simply realloc() down, since it might be wrapped.
1102 * To understand the arithmetic below, note that we are
1103 * copying into new positions 0 .. N-1 from old positions
1104 * old_key_next-N .. old_key_next-1, modulo old_key_len,
1105 * where N = pw_history_num - 1 is the length of the
1106 * shortened list. Matt Crawford, FNAL
1109 * M = adb->old_key_len, N = pol->pw_history_num - 1
1111 * tmp[0] .. tmp[N-1] = old[(knext-N)%M] .. old[(knext-1)%M]
1116 tmp = (osa_pw_hist_ent *)
1117 malloc((nhist - 1) * sizeof (osa_pw_hist_ent));
1120 for (i = 0; i < nhist - 1; i++) {
1122 * Add nkeys once before taking remainder to avoid
1125 j = (i + nkeys + knext - (nhist - 1)) % nkeys;
1126 tmp[i] = adb->old_keys[j];
1128 /* Now free the ones we don't keep (the oldest ones) */
1129 for (i = 0; i < nkeys - (nhist - 1); i++) {
1130 j = (i + nkeys + knext) % nkeys;
1131 histp = &adb->old_keys[j];
1132 for (j = 0; j < histp->n_key_data; j++) {
1133 krb5_free_key_data_contents(context, &histp->key_data[j]);
1135 free(histp->key_data);
1137 free((void *)adb->old_keys);
1138 adb->old_keys = tmp;
1139 nkeys = adb->old_key_len = nhist - 1;
1140 knext = adb->old_key_next = 0;
1144 * If nhist decreased since the last password change, and nkeys+1
1145 * is less than the previous nhist, it is possible for knext to
1146 * index into unallocated space. This condition would not be
1147 * caught by the resizing code above.
1149 if (knext + 1 > nkeys)
1150 knext = adb->old_key_next = 0;
1151 /* free the old pw history entry if it contains data */
1152 histp = &adb->old_keys[knext];
1153 for (i = 0; i < histp->n_key_data; i++)
1154 krb5_free_key_data_contents(context, &histp->key_data[i]);
1155 free(histp->key_data);
1157 /* store the new entry */
1158 adb->old_keys[knext] = *pw;
1160 /* update the next pointer */
1161 if (++adb->old_key_next == nhist - 1)
1162 adb->old_key_next = 0;
1167 #ifdef USE_PASSWORD_SERVER
1169 /* FIXME: don't use global variable for this */
1170 krb5_boolean use_password_server = 0;
1173 kadm5_use_password_server (void)
1175 return use_password_server;
1179 kadm5_set_use_password_server (void)
1181 use_password_server = 1;
1185 * kadm5_launch_task () runs a program (task_path) to synchronize the
1186 * Apple password server with the Kerberos database. Password server
1187 * programs can receive arguments on the command line (task_argv)
1188 * and a block of data via stdin (data_buffer).
1190 * Because a failure to communicate with the tool results in the
1191 * password server falling out of sync with the database,
1192 * kadm5_launch_task() always fails if it can't talk to the tool.
1196 kadm5_launch_task (krb5_context context,
1197 const char *task_path, char * const task_argv[],
1198 const char *data_buffer)
1200 kadm5_ret_t ret = 0;
1203 if (data_buffer != NULL) {
1204 ret = pipe (data_pipe);
1205 if (ret) { ret = errno; }
1209 pid_t pid = fork ();
1212 } else if (pid == 0) {
1215 if (data_buffer != NULL) {
1216 if (dup2 (data_pipe[0], STDIN_FILENO) == -1) {
1220 close (data_pipe[0]);
1223 close (data_pipe[1]);
1225 execv (task_path, task_argv);
1227 _exit (1); /* Fail if execv fails */
1232 if (data_buffer != NULL) {
1233 /* Write out the buffer to the child */
1234 if (krb5_net_write (context, data_pipe[1],
1235 data_buffer, strlen (data_buffer)) < 0) {
1236 /* kill the child to make sure waitpid() won't hang later */
1238 kill (pid, SIGKILL);
1242 close (data_buffer[0]);
1243 close (data_buffer[1]);
1245 waitpid (pid, &status, 0);
1248 if (WIFEXITED (status)) {
1249 /* child read password and exited. Check the return value. */
1250 if ((WEXITSTATUS (status) != 0) && (WEXITSTATUS (status) != 252)) {
1251 ret = KRB5KDC_ERR_POLICY; /* password change rejected */
1254 /* child read password but crashed or was killed */
1255 ret = KRB5KRB_ERR_GENERIC; /* FIXME: better error */
1267 kadm5_chpass_principal(void *server_handle,
1268 krb5_principal principal, char *password)
1271 kadm5_chpass_principal_3(server_handle, principal, FALSE,
1276 kadm5_chpass_principal_3(void *server_handle,
1277 krb5_principal principal, krb5_boolean keepold,
1278 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1282 kadm5_policy_ent_rec pol;
1283 osa_princ_ent_rec adb;
1284 krb5_db_entry kdb, kdb_save;
1285 int ret, ret2, last_pwd, hist_added;
1287 kadm5_server_handle_t handle = server_handle;
1288 osa_pw_hist_ent hist;
1290 CHECK_HANDLE(server_handle);
1292 krb5_db_clr_error();
1295 memset(&hist, 0, sizeof(hist));
1297 if (principal == NULL || password == NULL)
1299 if ((krb5_principal_compare(handle->context,
1300 principal, hist_princ)) == TRUE)
1301 return KADM5_PROTECT_PRINCIPAL;
1303 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1306 /* we are going to need the current keys after the new keys are set */
1307 if ((ret = kdb_get_entry(handle, principal, &kdb_save, NULL))) {
1308 kdb_free_entry(handle, &kdb, &adb);
1312 if ((adb.aux_attributes & KADM5_POLICY)) {
1313 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &pol)))
1318 if ((ret = passwd_check(handle, password, adb.aux_attributes &
1319 KADM5_POLICY, &pol, principal)))
1322 ret = krb5_dbe_cpw(handle->context, &master_keyblock,
1323 n_ks_tuple?ks_tuple:handle->params.keysalts,
1324 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
1325 password, 0 /* increment kvno */,
1330 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1332 ret = krb5_timeofday(handle->context, &now);
1336 if ((adb.aux_attributes & KADM5_POLICY)) {
1337 /* the policy was loaded before */
1339 ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1346 * The spec says this check is overridden if the caller has
1347 * modify privilege. The admin server therefore makes this
1348 * check itself (in chpass_principal_wrapper, misc.c). A
1349 * local caller implicitly has all authorization bits.
1351 if ((now - last_pwd) < pol.pw_min_life &&
1352 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1353 ret = KADM5_PASS_TOOSOON;
1358 ret = create_history_entry(handle->context,
1359 kdb_save.n_key_data,
1360 kdb_save.key_data, &hist);
1364 ret = check_pw_reuse(handle->context, &hist_key,
1365 kdb.n_key_data, kdb.key_data,
1370 if (pol.pw_history_num > 1) {
1371 if (adb.admin_history_kvno != hist_kvno) {
1372 ret = KADM5_BAD_HIST_KEY;
1376 ret = check_pw_reuse(handle->context, &hist_key,
1377 kdb.n_key_data, kdb.key_data,
1378 adb.old_key_len, adb.old_keys);
1382 ret = add_to_history(handle->context, &adb, &pol, &hist);
1388 if (pol.pw_max_life)
1389 kdb.pw_expiration = now + pol.pw_max_life;
1391 kdb.pw_expiration = 0;
1393 kdb.pw_expiration = 0;
1396 #ifdef USE_PASSWORD_SERVER
1397 if (kadm5_use_password_server () &&
1398 (krb5_princ_size (handle->context, principal) == 1)) {
1399 krb5_data *princ = krb5_princ_component (handle->context, principal, 0);
1400 const char *path = "/usr/sbin/mkpassdb";
1401 char *argv[] = { "mkpassdb", "-setpassword", NULL, NULL };
1402 char *pstring = NULL;
1404 int pwlen = strlen (password);
1406 if (pwlen > 254) pwlen = 254;
1407 strncpy (pwbuf, password, pwlen);
1408 pwbuf[pwlen] = '\n';
1409 pwbuf[pwlen + 1] = '\0';
1412 pstring = malloc ((princ->length + 1) * sizeof (char));
1413 if (pstring == NULL) { ret = errno; }
1417 memcpy (pstring, princ->data, princ->length);
1418 pstring [princ->length] = '\0';
1421 ret = kadm5_launch_task (handle->context, path, argv, pwbuf);
1424 if (pstring != NULL)
1432 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
1436 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1441 if (!hist_added && hist.key_data)
1442 free_history_entry(handle->context, &hist);
1443 kdb_free_entry(handle, &kdb, &adb);
1444 kdb_free_entry(handle, &kdb_save, NULL);
1445 krb5_db_free_principal(handle->context, &kdb, 1);
1447 if (have_pol && (ret2 = kadm5_free_policy_ent(handle->lhandle, &pol))
1455 kadm5_randkey_principal(void *server_handle,
1456 krb5_principal principal,
1457 krb5_keyblock **keyblocks,
1461 kadm5_randkey_principal_3(server_handle, principal,
1466 kadm5_randkey_principal_3(void *server_handle,
1467 krb5_principal principal,
1468 krb5_boolean keepold,
1469 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1470 krb5_keyblock **keyblocks,
1474 osa_princ_ent_rec adb;
1476 kadm5_policy_ent_rec pol;
1477 krb5_key_data *key_data;
1478 int ret, last_pwd, have_pol = 0;
1479 kadm5_server_handle_t handle = server_handle;
1481 krb5_db_clr_error();
1486 CHECK_HANDLE(server_handle);
1488 if (principal == NULL)
1490 if (hist_princ && /* this will be NULL when initializing the databse */
1491 ((krb5_principal_compare(handle->context,
1492 principal, hist_princ)) == TRUE))
1493 return KADM5_PROTECT_PRINCIPAL;
1495 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1498 ret = krb5_dbe_crk(handle->context, &master_keyblock,
1499 n_ks_tuple?ks_tuple:handle->params.keysalts,
1500 n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
1506 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1508 ret = krb5_timeofday(handle->context, &now);
1512 if ((adb.aux_attributes & KADM5_POLICY)) {
1513 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1518 ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1525 * The spec says this check is overridden if the caller has
1526 * modify privilege. The admin server therefore makes this
1527 * check itself (in chpass_principal_wrapper, misc.c). A
1528 * local caller implicitly has all authorization bits.
1530 if((now - last_pwd) < pol.pw_min_life &&
1531 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1532 ret = KADM5_PASS_TOOSOON;
1537 if(pol.pw_history_num > 1) {
1538 if(adb.admin_history_kvno != hist_kvno) {
1539 ret = KADM5_BAD_HIST_KEY;
1543 ret = check_pw_reuse(handle->context, &hist_key,
1544 kdb.n_key_data, kdb.key_data,
1545 adb.old_key_len, adb.old_keys);
1549 if (pol.pw_max_life)
1550 kdb.pw_expiration = now + pol.pw_max_life;
1552 kdb.pw_expiration = 0;
1554 kdb.pw_expiration = 0;
1557 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
1562 if (handle->api_version == KADM5_API_VERSION_1) {
1563 /* Version 1 clients will expect to see a DES_CRC enctype. */
1564 ret = krb5_dbe_find_enctype(handle->context, &kdb,
1565 ENCTYPE_DES_CBC_CRC,
1570 ret = decrypt_key_data(handle->context, 1, key_data,
1575 ret = decrypt_key_data(handle->context,
1576 kdb.n_key_data, kdb.key_data,
1583 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1588 kdb_free_entry(handle, &kdb, &adb);
1590 kadm5_free_policy_ent(handle->lhandle, &pol);
1596 * kadm5_setv4key_principal:
1598 * Set only ONE key of the principal, removing all others. This key
1599 * must have the DES_CBC_CRC enctype and is entered as having the
1600 * krb4 salttype. This is to enable things like kadmind4 to work.
1603 kadm5_setv4key_principal(void *server_handle,
1604 krb5_principal principal,
1605 krb5_keyblock *keyblock)
1608 osa_princ_ent_rec adb;
1610 kadm5_policy_ent_rec pol;
1611 krb5_keysalt keysalt;
1612 int i, k, kvno, ret, have_pol = 0;
1616 kadm5_server_handle_t handle = server_handle;
1617 krb5_key_data tmp_key_data;
1619 krb5_db_clr_error();
1621 memset( &tmp_key_data, 0, sizeof(tmp_key_data));
1623 CHECK_HANDLE(server_handle);
1625 if (principal == NULL || keyblock == NULL)
1627 if (hist_princ && /* this will be NULL when initializing the databse */
1628 ((krb5_principal_compare(handle->context,
1629 principal, hist_princ)) == TRUE))
1630 return KADM5_PROTECT_PRINCIPAL;
1632 if (keyblock->enctype != ENCTYPE_DES_CBC_CRC)
1633 return KADM5_SETV4KEY_INVAL_ENCTYPE;
1635 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1638 for (kvno = 0, i=0; i<kdb.n_key_data; i++)
1639 if (kdb.key_data[i].key_data_kvno > kvno)
1640 kvno = kdb.key_data[i].key_data_kvno;
1642 if (kdb.key_data != NULL)
1643 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
1645 kdb.key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, sizeof(krb5_key_data));
1646 if (kdb.key_data == NULL)
1648 memset(kdb.key_data, 0, sizeof(krb5_key_data));
1650 keysalt.type = KRB5_KDB_SALTTYPE_V4;
1651 /* XXX data.magic? */
1652 keysalt.data.length = 0;
1653 keysalt.data.data = NULL;
1655 /* use tmp_key_data as temporary location and reallocate later */
1656 ret = krb5_dbekd_encrypt_key_data(handle->context, &master_keyblock,
1657 keyblock, &keysalt, kvno + 1,
1663 for( k = 0; k < tmp_key_data.key_data_ver; k++ )
1665 kdb.key_data->key_data_type[k] = tmp_key_data.key_data_type[k];
1666 kdb.key_data->key_data_length[k] = tmp_key_data.key_data_length[k];
1667 if( tmp_key_data.key_data_contents[k] )
1669 kdb.key_data->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]);
1670 if( kdb.key_data->key_data_contents[k] == NULL )
1672 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
1673 kdb.key_data = NULL;
1678 memcpy( kdb.key_data->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
1680 memset( tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
1681 free( tmp_key_data.key_data_contents[k] );
1682 tmp_key_data.key_data_contents[k] = NULL;
1688 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1690 ret = krb5_timeofday(handle->context, &now);
1694 if ((adb.aux_attributes & KADM5_POLICY)) {
1695 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1702 * The spec says this check is overridden if the caller has
1703 * modify privilege. The admin server therefore makes this
1704 * check itself (in chpass_principal_wrapper, misc.c). A
1705 * local caller implicitly has all authorization bits.
1707 if (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1710 if((now - last_pwd) < pol.pw_min_life &&
1711 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1712 ret = KADM5_PASS_TOOSOON;
1718 * Should we be checking/updating pw history here?
1720 if(pol.pw_history_num > 1) {
1721 if(adb.admin_history_kvno != hist_kvno) {
1722 ret = KADM5_BAD_HIST_KEY;
1726 if (ret = check_pw_reuse(handle->context,
1728 kdb.n_key_data, kdb.key_data,
1729 adb.old_key_len, adb.old_keys))
1734 if (pol.pw_max_life)
1735 kdb.pw_expiration = now + pol.pw_max_life;
1737 kdb.pw_expiration = 0;
1739 kdb.pw_expiration = 0;
1742 ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
1746 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1751 for( i = 0; i < tmp_key_data.key_data_ver; i++ )
1753 if( tmp_key_data.key_data_contents[i] )
1755 memset( tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]);
1756 free( tmp_key_data.key_data_contents[i] );
1760 kdb_free_entry(handle, &kdb, &adb);
1762 kadm5_free_policy_ent(handle->lhandle, &pol);
1768 kadm5_setkey_principal(void *server_handle,
1769 krb5_principal principal,
1770 krb5_keyblock *keyblocks,
1774 kadm5_setkey_principal_3(server_handle, principal,
1780 kadm5_setkey_principal_3(void *server_handle,
1781 krb5_principal principal,
1782 krb5_boolean keepold,
1783 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
1784 krb5_keyblock *keyblocks,
1788 osa_princ_ent_rec adb;
1790 kadm5_policy_ent_rec pol;
1791 krb5_key_data *old_key_data;
1793 int i, j, k, kvno, ret, have_pol = 0;
1797 kadm5_server_handle_t handle = server_handle;
1798 krb5_boolean similar;
1799 krb5_keysalt keysalt;
1800 krb5_key_data tmp_key_data;
1801 krb5_key_data *tptr;
1803 CHECK_HANDLE(server_handle);
1805 krb5_db_clr_error();
1807 if (principal == NULL || keyblocks == NULL)
1809 if (hist_princ && /* this will be NULL when initializing the databse */
1810 ((krb5_principal_compare(handle->context,
1811 principal, hist_princ)) == TRUE))
1812 return KADM5_PROTECT_PRINCIPAL;
1814 for (i = 0; i < n_keys; i++) {
1815 for (j = i+1; j < n_keys; j++) {
1816 if ((ret = krb5_c_enctype_compare(handle->context,
1817 keyblocks[i].enctype,
1818 keyblocks[j].enctype,
1823 if (ks_tuple[i].ks_salttype == ks_tuple[j].ks_salttype)
1824 return KADM5_SETKEY_DUP_ENCTYPES;
1826 return KADM5_SETKEY_DUP_ENCTYPES;
1831 if (n_ks_tuple && n_ks_tuple != n_keys)
1832 return KADM5_SETKEY3_ETYPE_MISMATCH;
1834 if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
1837 for (kvno = 0, i=0; i<kdb.n_key_data; i++)
1838 if (kdb.key_data[i].key_data_kvno > kvno)
1839 kvno = kdb.key_data[i].key_data_kvno;
1842 old_key_data = kdb.key_data;
1843 n_old_keys = kdb.n_key_data;
1845 if (kdb.key_data != NULL)
1846 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
1848 old_key_data = NULL;
1851 kdb.key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, (n_keys+n_old_keys)
1852 *sizeof(krb5_key_data));
1853 if (kdb.key_data == NULL)
1859 memset(kdb.key_data, 0, (n_keys+n_old_keys)*sizeof(krb5_key_data));
1862 for (i = 0; i < n_keys; i++) {
1864 keysalt.type = ks_tuple[i].ks_salttype;
1865 keysalt.data.length = 0;
1866 keysalt.data.data = NULL;
1867 if (ks_tuple[i].ks_enctype != keyblocks[i].enctype) {
1868 ret= KADM5_SETKEY3_ETYPE_MISMATCH;
1872 memset( &tmp_key_data, 0, sizeof(tmp_key_data));
1874 ret = krb5_dbekd_encrypt_key_data(handle->context,
1877 n_ks_tuple ? &keysalt : NULL,
1883 tptr = &kdb.key_data[i];
1884 for( k = 0; k < tmp_key_data.key_data_ver; k++ )
1886 tptr->key_data_type[k] = tmp_key_data.key_data_type[k];
1887 tptr->key_data_length[k] = tmp_key_data.key_data_length[k];
1888 if( tmp_key_data.key_data_contents[k] )
1890 tptr->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]);
1891 if( tptr->key_data_contents[k] == NULL )
1894 for( i1 = k; i1 < tmp_key_data.key_data_ver; i1++ )
1896 if( tmp_key_data.key_data_contents[i1] )
1898 memset( tmp_key_data.key_data_contents[i1], 0, tmp_key_data.key_data_length[i1]);
1899 free( tmp_key_data.key_data_contents[i1] );
1906 memcpy( tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
1908 memset( tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
1909 free( tmp_key_data.key_data_contents[k] );
1910 tmp_key_data.key_data_contents[k] = NULL;
1916 /* copy old key data if necessary */
1917 for (i = 0; i < n_old_keys; i++) {
1918 kdb.key_data[i+n_keys] = old_key_data[i];
1919 memset(&old_key_data[i], 0, sizeof (krb5_key_data));
1924 krb5_db_free(handle->context, old_key_data);
1926 /* assert(kdb.n_key_data == n_keys + n_old_keys) */
1927 kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
1929 if ((ret = krb5_timeofday(handle->context, &now)))
1932 if ((adb.aux_attributes & KADM5_POLICY)) {
1933 if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
1940 * The spec says this check is overridden if the caller has
1941 * modify privilege. The admin server therefore makes this
1942 * check itself (in chpass_principal_wrapper, misc.c). A
1943 * local caller implicitly has all authorization bits.
1945 if (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
1948 if((now - last_pwd) < pol.pw_min_life &&
1949 !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
1950 ret = KADM5_PASS_TOOSOON;
1956 * Should we be checking/updating pw history here?
1958 if(pol.pw_history_num > 1) {
1959 if(adb.admin_history_kvno != hist_kvno) {
1960 ret = KADM5_BAD_HIST_KEY;
1964 if (ret = check_pw_reuse(handle->context,
1966 kdb.n_key_data, kdb.key_data,
1967 adb.old_key_len, adb.old_keys))
1972 if (pol.pw_max_life)
1973 kdb.pw_expiration = now + pol.pw_max_life;
1975 kdb.pw_expiration = 0;
1977 kdb.pw_expiration = 0;
1980 if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now)))
1983 if ((ret = kdb_put_entry(handle, &kdb, &adb)))
1988 kdb_free_entry(handle, &kdb, &adb);
1990 kadm5_free_policy_ent(handle->lhandle, &pol);
1996 * Allocate an array of n_key_data krb5_keyblocks, fill in each
1997 * element with the results of decrypting the nth key in key_data with
1998 * master_keyblock, and if n_keys is not NULL fill it in with the
1999 * number of keys decrypted.
2001 static int decrypt_key_data(krb5_context context,
2002 int n_key_data, krb5_key_data *key_data,
2003 krb5_keyblock **keyblocks, int *n_keys)
2005 krb5_keyblock *keys;
2008 keys = (krb5_keyblock *) malloc(n_key_data*sizeof(krb5_keyblock));
2011 memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock));
2013 for (i = 0; i < n_key_data; i++) {
2014 ret = krb5_dbekd_decrypt_key_data(context, &master_keyblock,
2020 if( keys[i].contents )
2022 memset( keys[i].contents, 0, keys[i].length );
2023 free( keys[i].contents );
2027 memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock));
2035 *n_keys = n_key_data;
2041 * Function: kadm5_decrypt_key
2043 * Purpose: Retrieves and decrypts a principal key.
2047 * server_handle (r) kadm5 handle
2048 * entry (r) principal retrieved with kadm5_get_principal
2049 * ktype (r) enctype to search for, or -1 to ignore
2050 * stype (r) salt type to search for, or -1 to ignore
2051 * kvno (r) kvno to search for, -1 for max, 0 for max
2052 * only if it also matches ktype and stype
2053 * keyblock (w) keyblock to fill in
2054 * keysalt (w) keysalt to fill in, or NULL
2055 * kvnop (w) kvno to fill in, or NULL
2057 * Effects: Searches the key_data array of entry, which must have been
2058 * retrived with kadm5_get_principal with the KADM5_KEY_DATA mask, to
2059 * find a key with a specified enctype, salt type, and kvno in a
2060 * principal entry. If not found, return ENOENT. Otherwise, decrypt
2061 * it with the master key, and return the key in keyblock, the salt
2062 * in salttype, and the key version number in kvno.
2064 * If ktype or stype is -1, it is ignored for the search. If kvno is
2065 * -1, ktype and stype are ignored and the key with the max kvno is
2066 * returned. If kvno is 0, only the key with the max kvno is returned
2067 * and only if it matches the ktype and stype; otherwise, ENOENT is
2070 kadm5_ret_t kadm5_decrypt_key(void *server_handle,
2071 kadm5_principal_ent_t entry, krb5_int32
2072 ktype, krb5_int32 stype, krb5_int32
2073 kvno, krb5_keyblock *keyblock,
2074 krb5_keysalt *keysalt, int *kvnop)
2076 kadm5_server_handle_t handle = server_handle;
2077 krb5_db_entry dbent;
2078 krb5_key_data *key_data;
2081 CHECK_HANDLE(server_handle);
2083 if (entry->n_key_data == 0 || entry->key_data == NULL)
2086 /* find_enctype only uses these two fields */
2087 dbent.n_key_data = entry->n_key_data;
2088 dbent.key_data = entry->key_data;
2089 if ((ret = krb5_dbe_find_enctype(handle->context, &dbent, ktype,
2090 stype, kvno, &key_data)))
2093 if ((ret = krb5_dbekd_decrypt_key_data(handle->context,
2094 &master_keyblock, key_data,
2095 keyblock, keysalt)))
2099 * Coerce the enctype of the output keyblock in case we got an
2100 * inexact match on the enctype; this behavior will go away when
2101 * the key storage architecture gets redesigned for 1.3.
2103 keyblock->enctype = ktype;
2106 *kvnop = key_data->key_data_kvno;