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.
60 get_key_data_kvno(context, count, data)
66 /* Find last key version number */
67 for (kvno = i = 0; i < count; i++) {
68 if (kvno < data[i].key_data_kvno) {
69 kvno = data[i].key_data_kvno;
76 cleanup_key_data(context, count, data)
83 for (i = 0; i < count; i++) {
84 for (j = 0; j < data[i].key_data_ver; j++) {
85 if (data[i].key_data_length[j]) {
86 free(data[i].key_data_contents[j]);
93 static krb5_error_code
94 add_key_rnd(context, master_key, ks_tuple, ks_tuple_count, db_entry, kvno)
96 krb5_keyblock * master_key;
97 krb5_key_salt_tuple * ks_tuple;
99 krb5_db_entry * db_entry;
102 krb5_principal krbtgt_princ;
104 krb5_db_entry krbtgt_entry;
106 int max_kvno, one, i, j;
107 krb5_error_code retval;
109 retval = krb5_build_principal_ext(context, &krbtgt_princ,
110 db_entry->princ->realm.length,
111 db_entry->princ->realm.data,
114 db_entry->princ->realm.length,
115 db_entry->princ->realm.data,
120 /* Get tgt from database */
121 retval = krb5_db_get_principal(context, krbtgt_princ, &krbtgt_entry,
123 krb5_free_principal(context, krbtgt_princ); /* don't need it anymore */
126 if ((one > 1) || (more)) {
127 krb5_db_free_principal(context, &krbtgt_entry, one);
128 return KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
131 return KRB5_KDB_NOENTRY;
134 for (max_kvno = j = 0; j < krbtgt_entry.n_key_data; j++) {
135 if (max_kvno < krbtgt_entry.key_data[j].key_data_kvno) {
136 max_kvno = krbtgt_entry.key_data[j].key_data_kvno;
140 for (i = 0; i < ks_tuple_count; i++) {
141 krb5_boolean similar;
146 * We could use krb5_keysalt_iterate to replace this loop, or use
147 * krb5_keysalt_is_present for the loop below, but we want to avoid
148 * circular library dependencies.
150 for (j = 0; j < i; j++) {
151 if ((retval = krb5_c_enctype_compare(context,
152 ks_tuple[i].ks_enctype,
153 ks_tuple[j].ks_enctype,
164 if ((retval = krb5_dbe_create_key_data(context, db_entry)))
165 goto add_key_rnd_err;
167 /* there used to be code here to extract the old key, and derive
168 a new key from it. Now that there's a unified prng, that isn't
172 if ((retval = krb5_c_make_random_key(context, ks_tuple[i].ks_enctype,
174 goto add_key_rnd_err;
176 retval = krb5_dbekd_encrypt_key_data(context, master_key,
178 &db_entry->key_data[db_entry->n_key_data-1]);
180 krb5_free_keyblock_contents(context, &key);
183 goto add_key_rnd_err;
187 krb5_db_free_principal(context, &krbtgt_entry, one);
193 * Change random key for a krb5_db_entry
194 * Assumes the max kvno
196 * As a side effect all old keys are nuked if keepold is false.
199 krb5_dbe_crk(context, master_key, ks_tuple, ks_tuple_count, keepold, db_entry)
200 krb5_context context;
201 krb5_keyblock * master_key;
202 krb5_key_salt_tuple * ks_tuple;
204 krb5_boolean keepold;
205 krb5_db_entry * db_entry;
209 krb5_key_data * key_data;
210 krb5_error_code retval;
214 /* First save the old keydata */
215 kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
216 key_data_count = db_entry->n_key_data;
217 key_data = db_entry->key_data;
218 db_entry->key_data = NULL;
219 db_entry->n_key_data = 0;
221 /* increment the kvno */
224 retval = add_key_rnd(context, master_key, ks_tuple,
225 ks_tuple_count, db_entry, kvno);
227 cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
228 db_entry->n_key_data = key_data_count;
229 db_entry->key_data = key_data;
230 } else if (keepold) {
231 n_new_key_data = db_entry->n_key_data;
232 for (i = 0; i < key_data_count; i++) {
233 retval = krb5_dbe_create_key_data(context, db_entry);
235 cleanup_key_data(context, db_entry->n_key_data,
239 db_entry->key_data[i+n_new_key_data] = key_data[i];
240 memset(&key_data[i], 0, sizeof(krb5_key_data));
243 cleanup_key_data(context, key_data_count, key_data);
249 * Add random key for a krb5_db_entry
250 * Assumes the max kvno
252 * As a side effect all old keys older than the max kvno are nuked.
255 krb5_dbe_ark(context, master_key, ks_tuple, ks_tuple_count, db_entry)
256 krb5_context context;
257 krb5_keyblock * master_key;
258 krb5_key_salt_tuple * ks_tuple;
260 krb5_db_entry * db_entry;
263 krb5_key_data * key_data;
264 krb5_error_code retval;
268 /* First save the old keydata */
269 kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
270 key_data_count = db_entry->n_key_data;
271 key_data = db_entry->key_data;
272 db_entry->key_data = NULL;
273 db_entry->n_key_data = 0;
275 /* increment the kvno */
278 if ((retval = add_key_rnd(context, master_key, ks_tuple,
279 ks_tuple_count, db_entry, kvno))) {
280 cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
281 db_entry->n_key_data = key_data_count;
282 db_entry->key_data = key_data;
284 /* Copy keys with key_data_kvno == kvno - 1 ( = old kvno ) */
285 for (i = 0; i < key_data_count; i++) {
286 if (key_data[i].key_data_kvno == (kvno - 1)) {
287 if ((retval = krb5_dbe_create_key_data(context, db_entry))) {
288 cleanup_key_data(context, db_entry->n_key_data,
292 /* We should decrypt/re-encrypt the data to use the same mkvno*/
293 db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
294 memset(&key_data[i], 0, sizeof(krb5_key_data));
297 cleanup_key_data(context, key_data_count, key_data);
303 * Add key_data for a krb5_db_entry
304 * If passwd is NULL the assumes that the caller wants a random password.
306 static krb5_error_code
307 add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, passwd,
309 krb5_context context;
310 krb5_keyblock * master_key;
311 krb5_key_salt_tuple * ks_tuple;
314 krb5_db_entry * db_entry;
317 krb5_error_code retval;
318 krb5_keysalt key_salt;
325 for (i = 0; i < ks_tuple_count; i++) {
326 krb5_boolean similar;
331 * We could use krb5_keysalt_iterate to replace this loop, or use
332 * krb5_keysalt_is_present for the loop below, but we want to avoid
333 * circular library dependencies.
335 for (j = 0; j < i; j++) {
336 if ((retval = krb5_c_enctype_compare(context,
337 ks_tuple[i].ks_enctype,
338 ks_tuple[j].ks_enctype,
343 (ks_tuple[j].ks_salttype == ks_tuple[i].ks_salttype))
350 if ((retval = krb5_dbe_create_key_data(context, db_entry)))
353 /* Convert password string to key using appropriate salt */
354 switch (key_salt.type = ks_tuple[i].ks_salttype) {
355 case KRB5_KDB_SALTTYPE_ONLYREALM: {
356 krb5_data * saltdata;
357 if ((retval = krb5_copy_data(context, krb5_princ_realm(context,
358 db_entry->princ), &saltdata)))
361 key_salt.data = *saltdata;
362 krb5_xfree(saltdata);
365 case KRB5_KDB_SALTTYPE_NOREALM:
366 if ((retval=krb5_principal2salt_norealm(context, db_entry->princ,
370 case KRB5_KDB_SALTTYPE_NORMAL:
371 if ((retval = krb5_principal2salt(context, db_entry->princ,
375 case KRB5_KDB_SALTTYPE_V4:
376 key_salt.data.length = 0;
377 key_salt.data.data = 0;
379 case KRB5_KDB_SALTTYPE_AFS3: {
381 krb5_data * saltdata;
382 if (retval = krb5_copy_data(context, krb5_princ_realm(context,
383 db_entry->princ), &saltdata))
386 key_salt.data = *saltdata;
387 key_salt.data.length = SALT_TYPE_AFS_LENGTH; /*length actually used below...*/
388 krb5_xfree(saltdata);
390 /* Why do we do this? Well, the afs_mit_string_to_key needs to
391 use strlen, and the realm is not NULL terminated.... */
392 int slen = (*krb5_princ_realm(context,db_entry->princ)).length;
393 if(!(key_salt.data.data = (char *) malloc(slen+1)))
395 key_salt.data.data[slen] = 0;
396 memcpy((char *)key_salt.data.data,
397 (char *)(*krb5_princ_realm(context,db_entry->princ)).data,
399 key_salt.data.length = SALT_TYPE_AFS_LENGTH; /*length actually used below...*/
405 return(KRB5_KDB_BAD_SALTTYPE);
409 pwd.length = strlen(passwd);
411 /* AFS string to key will happen here */
412 if ((retval = krb5_c_string_to_key(context, ks_tuple[i].ks_enctype,
413 &pwd, &key_salt.data, &key))) {
414 if (key_salt.data.data)
415 free(key_salt.data.data);
419 if (key_salt.data.length == SALT_TYPE_AFS_LENGTH)
420 key_salt.data.length =
421 krb5_princ_realm(context, db_entry->princ)->length;
423 if ((retval = krb5_dbekd_encrypt_key_data(context, master_key, &key,
424 (const krb5_keysalt *)&key_salt,
425 kvno, &db_entry->key_data[db_entry->n_key_data-1]))) {
426 if (key_salt.data.data)
427 free(key_salt.data.data);
428 krb5_xfree(key.contents);
431 if (key_salt.data.data)
432 free(key_salt.data.data);
433 krb5_xfree(key.contents);
439 * Change password for a krb5_db_entry
440 * Assumes the max kvno
442 * As a side effect all old keys are nuked if keepold is false.
445 krb5_dbe_cpw(context, master_key, ks_tuple, ks_tuple_count, passwd,
446 new_kvno, keepold, db_entry)
447 krb5_context context;
448 krb5_keyblock * master_key;
449 krb5_key_salt_tuple * ks_tuple;
453 krb5_boolean keepold;
454 krb5_db_entry * db_entry;
458 krb5_key_data * key_data;
459 krb5_error_code retval;
463 /* First save the old keydata */
464 old_kvno = get_key_data_kvno(context, db_entry->n_key_data,
466 key_data_count = db_entry->n_key_data;
467 key_data = db_entry->key_data;
468 db_entry->key_data = NULL;
469 db_entry->n_key_data = 0;
471 /* increment the kvno. if the requested kvno is too small,
472 increment the old kvno */
473 if (new_kvno < old_kvno+1)
474 new_kvno = old_kvno+1;
476 retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count,
477 passwd, db_entry, new_kvno);
479 cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
480 db_entry->n_key_data = key_data_count;
481 db_entry->key_data = key_data;
482 } else if (keepold) {
483 n_new_key_data = db_entry->n_key_data;
484 for (i = 0; i < key_data_count; i++) {
485 retval = krb5_dbe_create_key_data(context, db_entry);
487 cleanup_key_data(context, db_entry->n_key_data,
491 db_entry->key_data[i+n_new_key_data] = key_data[i];
492 memset(&key_data[i], 0, sizeof(krb5_key_data));
495 cleanup_key_data(context, key_data_count, key_data);
501 * Add password for a krb5_db_entry
502 * Assumes the max kvno
504 * As a side effect all old keys older than the max kvno are nuked.
507 krb5_dbe_apw(context, master_key, ks_tuple, ks_tuple_count, passwd, db_entry)
508 krb5_context context;
509 krb5_keyblock * master_key;
510 krb5_key_salt_tuple * ks_tuple;
513 krb5_db_entry * db_entry;
516 krb5_key_data * key_data;
517 krb5_error_code retval;
518 int old_kvno, new_kvno;
521 /* First save the old keydata */
522 old_kvno = get_key_data_kvno(context, db_entry->n_key_data,
524 key_data_count = db_entry->n_key_data;
525 key_data = db_entry->key_data;
526 db_entry->key_data = NULL;
527 db_entry->n_key_data = 0;
529 /* increment the kvno */
530 new_kvno = old_kvno+1;
532 if ((retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count,
533 passwd, db_entry, new_kvno))) {
534 cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
535 db_entry->n_key_data = key_data_count;
536 db_entry->key_data = key_data;
538 /* Copy keys with key_data_kvno == old_kvno */
539 for (i = 0; i < key_data_count; i++) {
540 if (key_data[i].key_data_kvno == old_kvno) {
541 if ((retval = krb5_dbe_create_key_data(context, db_entry))) {
542 cleanup_key_data(context, db_entry->n_key_data,
546 /* We should decrypt/re-encrypt the data to use the same mkvno*/
547 db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
548 memset(&key_data[i], 0, sizeof(krb5_key_data));
551 cleanup_key_data(context, key_data_count, key_data);