4 * Copyright 1995 by the Massachusetts Institute of Technology.
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
29 * Copyright (C) 1998 by the FundsXpress, INC.
31 * All rights reserved.
33 * Export of this software from the United States of America may require
34 * a specific license from the United States Government. It is the
35 * responsibility of any person or organization contemplating export to
36 * obtain such a license before exporting.
38 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
39 * distribute this software and its documentation for any purpose and
40 * without fee is hereby granted, provided that the above copyright
41 * notice appear in all copies and that both that copyright notice and
42 * this permission notice appear in supporting documentation, and that
43 * the name of FundsXpress. not be used in advertising or publicity pertaining
44 * to distribution of the software without specific, written prior
45 * permission. FundsXpress makes no representations about the suitability of
46 * this software for any purpose. It is provided "as is" without express
47 * or implied warranty.
49 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
50 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
51 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
59 get_key_data_kvno(context, count, data)
65 /* Find last key version number */
66 for (kvno = i = 0; i < count; i++) {
67 if (kvno < data[i].key_data_kvno) {
68 kvno = data[i].key_data_kvno;
75 cleanup_key_data(context, count, data)
82 /* If data is NULL, count is always 0 */
83 if (data == NULL) return;
85 for (i = 0; i < count; i++) {
86 for (j = 0; j < data[i].key_data_ver; j++) {
87 if (data[i].key_data_length[j]) {
88 krb5_db_free(context, data[i].key_data_contents[j]);
92 krb5_db_free(context, data);
95 static krb5_error_code
96 add_key_rnd(context, master_key, ks_tuple, ks_tuple_count, db_entry, kvno)
98 krb5_keyblock * master_key;
99 krb5_key_salt_tuple * ks_tuple;
101 krb5_db_entry * db_entry;
104 krb5_principal krbtgt_princ;
106 krb5_db_entry krbtgt_entry;
108 int max_kvno, one, i, j, k;
109 krb5_error_code retval;
110 krb5_key_data tmp_key_data;
113 memset( &tmp_key_data, 0, sizeof(tmp_key_data));
116 retval = krb5_build_principal_ext(context, &krbtgt_princ,
117 db_entry->princ->realm.length,
118 db_entry->princ->realm.data,
121 db_entry->princ->realm.length,
122 db_entry->princ->realm.data,
127 /* Get tgt from database */
128 retval = krb5_db_get_principal(context, krbtgt_princ, &krbtgt_entry,
130 krb5_free_principal(context, krbtgt_princ); /* don't need it anymore */
133 if ((one > 1) || (more)) {
134 krb5_db_free_principal(context, &krbtgt_entry, one);
135 return KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
138 return KRB5_KDB_NOENTRY;
141 for (max_kvno = j = 0; j < krbtgt_entry.n_key_data; j++) {
142 if (max_kvno < krbtgt_entry.key_data[j].key_data_kvno) {
143 max_kvno = krbtgt_entry.key_data[j].key_data_kvno;
147 for (i = 0; i < ks_tuple_count; i++) {
148 krb5_boolean similar;
153 * We could use krb5_keysalt_iterate to replace this loop, or use
154 * krb5_keysalt_is_present for the loop below, but we want to avoid
155 * circular library dependencies.
157 for (j = 0; j < i; j++) {
158 if ((retval = krb5_c_enctype_compare(context,
159 ks_tuple[i].ks_enctype,
160 ks_tuple[j].ks_enctype,
171 if ((retval = krb5_dbe_create_key_data(context, db_entry)))
172 goto add_key_rnd_err;
174 /* there used to be code here to extract the old key, and derive
175 a new key from it. Now that there's a unified prng, that isn't
179 if ((retval = krb5_c_make_random_key(context, ks_tuple[i].ks_enctype,
181 goto add_key_rnd_err;
184 /* db library will free this. Since, its a so, it could actually be using different memory management
185 function. So, its better if the memory is allocated by the db's malloc. So, a temporary memory is used
186 here which will later be copied to the db_entry */
187 retval = krb5_dbekd_encrypt_key_data(context, master_key,
191 krb5_free_keyblock_contents(context, &key);
193 goto add_key_rnd_err;
195 tptr = &db_entry->key_data[db_entry->n_key_data-1];
197 tptr->key_data_ver = tmp_key_data.key_data_ver;
198 tptr->key_data_kvno = tmp_key_data.key_data_kvno;
200 for( k = 0; k < tmp_key_data.key_data_ver; k++ )
202 tptr->key_data_type[k] = tmp_key_data.key_data_type[k];
203 tptr->key_data_length[k] = tmp_key_data.key_data_length[k];
204 if( tmp_key_data.key_data_contents[k] )
206 tptr->key_data_contents[k] = krb5_db_alloc(context, NULL, tmp_key_data.key_data_length[k]);
207 if( tptr->key_data_contents[k] == NULL )
209 cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
210 db_entry->key_data = NULL;
211 db_entry->n_key_data = 0;
213 goto add_key_rnd_err;
215 memcpy( tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
217 memset( tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
218 free( tmp_key_data.key_data_contents[k] );
219 tmp_key_data.key_data_contents[k] = NULL;
226 krb5_db_free_principal(context, &krbtgt_entry, one);
228 for( i = 0; i < tmp_key_data.key_data_ver; i++ )
230 if( tmp_key_data.key_data_contents[i] )
232 memset( tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]);
233 free( tmp_key_data.key_data_contents[i] );
240 * Change random key for a krb5_db_entry
241 * Assumes the max kvno
243 * As a side effect all old keys are nuked if keepold is false.
246 krb5_dbe_crk(context, master_key, ks_tuple, ks_tuple_count, keepold, db_entry)
247 krb5_context context;
248 krb5_keyblock * master_key;
249 krb5_key_salt_tuple * ks_tuple;
251 krb5_boolean keepold;
252 krb5_db_entry * db_entry;
256 krb5_key_data * key_data;
257 krb5_error_code retval;
261 /* First save the old keydata */
262 kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
263 key_data_count = db_entry->n_key_data;
264 key_data = db_entry->key_data;
265 db_entry->key_data = NULL;
266 db_entry->n_key_data = 0;
268 /* increment the kvno */
271 retval = add_key_rnd(context, master_key, ks_tuple,
272 ks_tuple_count, db_entry, kvno);
274 cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
275 db_entry->n_key_data = key_data_count;
276 db_entry->key_data = key_data;
277 } else if (keepold) {
278 n_new_key_data = db_entry->n_key_data;
279 for (i = 0; i < key_data_count; i++) {
280 retval = krb5_dbe_create_key_data(context, db_entry);
282 cleanup_key_data(context, db_entry->n_key_data,
286 db_entry->key_data[i+n_new_key_data] = key_data[i];
287 memset(&key_data[i], 0, sizeof(krb5_key_data));
289 krb5_db_free(context, key_data); /* we moved the cotents to new memory. But, the original block which contained the data */
291 cleanup_key_data(context, key_data_count, key_data);
297 * Add random key for a krb5_db_entry
298 * Assumes the max kvno
300 * As a side effect all old keys older than the max kvno are nuked.
303 krb5_dbe_ark(context, master_key, ks_tuple, ks_tuple_count, db_entry)
304 krb5_context context;
305 krb5_keyblock * master_key;
306 krb5_key_salt_tuple * ks_tuple;
308 krb5_db_entry * db_entry;
311 krb5_key_data * key_data;
312 krb5_error_code retval;
316 /* First save the old keydata */
317 kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
318 key_data_count = db_entry->n_key_data;
319 key_data = db_entry->key_data;
320 db_entry->key_data = NULL;
321 db_entry->n_key_data = 0;
323 /* increment the kvno */
326 if ((retval = add_key_rnd(context, master_key, ks_tuple,
327 ks_tuple_count, db_entry, kvno))) {
328 cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
329 db_entry->n_key_data = key_data_count;
330 db_entry->key_data = key_data;
332 /* Copy keys with key_data_kvno == kvno - 1 ( = old kvno ) */
333 for (i = 0; i < key_data_count; i++) {
334 if (key_data[i].key_data_kvno == (kvno - 1)) {
335 if ((retval = krb5_dbe_create_key_data(context, db_entry))) {
336 cleanup_key_data(context, db_entry->n_key_data,
340 /* We should decrypt/re-encrypt the data to use the same mkvno*/
341 db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
342 memset(&key_data[i], 0, sizeof(krb5_key_data));
345 cleanup_key_data(context, key_data_count, key_data);
351 * Add key_data for a krb5_db_entry
352 * If passwd is NULL the assumes that the caller wants a random password.
354 static krb5_error_code
355 add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, passwd,
357 krb5_context context;
358 krb5_keyblock * master_key;
359 krb5_key_salt_tuple * ks_tuple;
362 krb5_db_entry * db_entry;
365 krb5_error_code retval;
366 krb5_keysalt key_salt;
370 krb5_key_data tmp_key_data;
373 memset( &tmp_key_data, 0, sizeof(tmp_key_data));
377 for (i = 0; i < ks_tuple_count; i++) {
378 krb5_boolean similar;
383 * We could use krb5_keysalt_iterate to replace this loop, or use
384 * krb5_keysalt_is_present for the loop below, but we want to avoid
385 * circular library dependencies.
387 for (j = 0; j < i; j++) {
388 if ((retval = krb5_c_enctype_compare(context,
389 ks_tuple[i].ks_enctype,
390 ks_tuple[j].ks_enctype,
395 (ks_tuple[j].ks_salttype == ks_tuple[i].ks_salttype))
402 if ((retval = krb5_dbe_create_key_data(context, db_entry)))
405 /* Convert password string to key using appropriate salt */
406 switch (key_salt.type = ks_tuple[i].ks_salttype) {
407 case KRB5_KDB_SALTTYPE_ONLYREALM: {
408 krb5_data * saltdata;
409 if ((retval = krb5_copy_data(context, krb5_princ_realm(context,
410 db_entry->princ), &saltdata)))
413 key_salt.data = *saltdata;
414 krb5_xfree(saltdata);
417 case KRB5_KDB_SALTTYPE_NOREALM:
418 if ((retval=krb5_principal2salt_norealm(context, db_entry->princ,
422 case KRB5_KDB_SALTTYPE_NORMAL:
423 if ((retval = krb5_principal2salt(context, db_entry->princ,
427 case KRB5_KDB_SALTTYPE_V4:
428 key_salt.data.length = 0;
429 key_salt.data.data = 0;
431 case KRB5_KDB_SALTTYPE_AFS3: {
433 krb5_data * saltdata;
434 if (retval = krb5_copy_data(context, krb5_princ_realm(context,
435 db_entry->princ), &saltdata))
438 key_salt.data = *saltdata;
439 key_salt.data.length = SALT_TYPE_AFS_LENGTH; /*length actually used below...*/
440 krb5_xfree(saltdata);
442 /* Why do we do this? Well, the afs_mit_string_to_key needs to
443 use strlen, and the realm is not NULL terminated.... */
445 (*krb5_princ_realm(context,db_entry->princ)).length;
446 if(!(key_salt.data.data = (char *) malloc(slen+1)))
448 key_salt.data.data[slen] = 0;
449 memcpy((char *)key_salt.data.data,
450 (char *)(*krb5_princ_realm(context,db_entry->princ)).data,
452 key_salt.data.length = SALT_TYPE_AFS_LENGTH; /*length actually used below...*/
458 return(KRB5_KDB_BAD_SALTTYPE);
462 pwd.length = strlen(passwd);
464 /* AFS string to key will happen here */
465 if ((retval = krb5_c_string_to_key(context, ks_tuple[i].ks_enctype,
466 &pwd, &key_salt.data, &key))) {
467 if (key_salt.data.data)
468 free(key_salt.data.data);
472 if (key_salt.data.length == SALT_TYPE_AFS_LENGTH)
473 key_salt.data.length =
474 krb5_princ_realm(context, db_entry->princ)->length;
476 /* memory allocation to be done by db. So, use temporary block and later copy
477 it to the memory allocated by db */
478 retval = krb5_dbekd_encrypt_key_data(context, master_key, &key,
479 (const krb5_keysalt *)&key_salt,
480 kvno, &tmp_key_data);
481 if (key_salt.data.data)
482 free(key_salt.data.data);
483 krb5_xfree(key.contents);
488 tptr = &db_entry->key_data[db_entry->n_key_data-1];
490 tptr->key_data_ver = tmp_key_data.key_data_ver;
491 tptr->key_data_kvno = tmp_key_data.key_data_kvno;
493 for( k = 0; k < tmp_key_data.key_data_ver; k++ )
495 tptr->key_data_type[k] = tmp_key_data.key_data_type[k];
496 tptr->key_data_length[k] = tmp_key_data.key_data_length[k];
497 if( tmp_key_data.key_data_contents[k] )
499 tptr->key_data_contents[k] = krb5_db_alloc(context, NULL, tmp_key_data.key_data_length[k]);
500 if( tptr->key_data_contents[k] == NULL )
502 cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
503 db_entry->key_data = NULL;
504 db_entry->n_key_data = 0;
506 goto add_key_pwd_err;
508 memcpy( tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
510 memset( tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
511 free( tmp_key_data.key_data_contents[k] );
512 tmp_key_data.key_data_contents[k] = NULL;
517 for( i = 0; i < tmp_key_data.key_data_ver; i++ )
519 if( tmp_key_data.key_data_contents[i] )
521 memset( tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]);
522 free( tmp_key_data.key_data_contents[i] );
530 * Change password for a krb5_db_entry
531 * Assumes the max kvno
533 * As a side effect all old keys are nuked if keepold is false.
536 krb5_dbe_def_cpw(context, master_key, ks_tuple, ks_tuple_count, passwd,
537 new_kvno, keepold, db_entry)
538 krb5_context context;
539 krb5_keyblock * master_key;
540 krb5_key_salt_tuple * ks_tuple;
544 krb5_boolean keepold;
545 krb5_db_entry * db_entry;
549 krb5_key_data * key_data;
550 krb5_error_code retval;
554 /* First save the old keydata */
555 old_kvno = get_key_data_kvno(context, db_entry->n_key_data,
557 key_data_count = db_entry->n_key_data;
558 key_data = db_entry->key_data;
559 db_entry->key_data = NULL;
560 db_entry->n_key_data = 0;
562 /* increment the kvno. if the requested kvno is too small,
563 increment the old kvno */
564 if (new_kvno < old_kvno+1)
565 new_kvno = old_kvno+1;
567 retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count,
568 passwd, db_entry, new_kvno);
570 cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
571 db_entry->n_key_data = key_data_count;
572 db_entry->key_data = key_data;
573 } else if (keepold) {
574 n_new_key_data = db_entry->n_key_data;
575 for (i = 0; i < key_data_count; i++) {
576 retval = krb5_dbe_create_key_data(context, db_entry);
578 cleanup_key_data(context, db_entry->n_key_data,
582 db_entry->key_data[i+n_new_key_data] = key_data[i];
583 memset(&key_data[i], 0, sizeof(krb5_key_data));
585 krb5_db_free( context, key_data );
587 cleanup_key_data(context, key_data_count, key_data);
593 * Add password for a krb5_db_entry
594 * Assumes the max kvno
596 * As a side effect all old keys older than the max kvno are nuked.
599 krb5_dbe_apw(context, master_key, ks_tuple, ks_tuple_count, passwd, db_entry)
600 krb5_context context;
601 krb5_keyblock * master_key;
602 krb5_key_salt_tuple * ks_tuple;
605 krb5_db_entry * db_entry;
608 krb5_key_data * key_data;
609 krb5_error_code retval;
610 int old_kvno, new_kvno;
613 /* First save the old keydata */
614 old_kvno = get_key_data_kvno(context, db_entry->n_key_data,
616 key_data_count = db_entry->n_key_data;
617 key_data = db_entry->key_data;
618 db_entry->key_data = NULL;
619 db_entry->n_key_data = 0;
621 /* increment the kvno */
622 new_kvno = old_kvno+1;
624 if ((retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count,
625 passwd, db_entry, new_kvno))) {
626 cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
627 db_entry->n_key_data = key_data_count;
628 db_entry->key_data = key_data;
630 /* Copy keys with key_data_kvno == old_kvno */
631 for (i = 0; i < key_data_count; i++) {
632 if (key_data[i].key_data_kvno == old_kvno) {
633 if ((retval = krb5_dbe_create_key_data(context, db_entry))) {
634 cleanup_key_data(context, db_entry->n_key_data,
638 /* We should decrypt/re-encrypt the data to use the same mkvno*/
639 db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
640 memset(&key_data[i], 0, sizeof(krb5_key_data));
643 cleanup_key_data(context, key_data_count, key_data);