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;
105 krb5_key_data * krbtgt_kdata;
107 int max_kvno, one, i, j;
108 krb5_error_code retval;
110 retval = krb5_build_principal_ext(context, &krbtgt_princ,
111 db_entry->princ->realm.length,
112 db_entry->princ->realm.data,
115 db_entry->princ->realm.length,
116 db_entry->princ->realm.data,
121 /* Get tgt from database */
122 retval = krb5_db_get_principal(context, krbtgt_princ, &krbtgt_entry,
124 krb5_free_principal(context, krbtgt_princ); /* don't need it anymore */
127 if ((one > 1) || (more)) {
128 krb5_db_free_principal(context, &krbtgt_entry, one);
129 return KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
132 return KRB5_KDB_NOENTRY;
135 for (max_kvno = j = 0; j < krbtgt_entry.n_key_data; j++) {
136 if (max_kvno < krbtgt_entry.key_data[j].key_data_kvno) {
137 max_kvno = krbtgt_entry.key_data[j].key_data_kvno;
141 for (i = 0; i < ks_tuple_count; i++) {
142 krb5_boolean similar;
147 * We could use krb5_keysalt_iterate to replace this loop, or use
148 * krb5_keysalt_is_present for the loop below, but we want to avoid
149 * circular library dependencies.
151 for (j = 0; j < i; j++) {
152 if ((retval = krb5_c_enctype_compare(context,
153 ks_tuple[i].ks_enctype,
154 ks_tuple[j].ks_enctype,
165 if (retval = krb5_dbe_create_key_data(context, db_entry))
166 goto add_key_rnd_err;
168 /* there used to be code here to extract the old key, and derive
169 a new key from it. Now that there's a unified prng, that isn't
173 if ((retval = krb5_c_make_random_key(context, ks_tuple[i].ks_enctype,
175 goto add_key_rnd_err;
177 retval = krb5_dbekd_encrypt_key_data(context, master_key,
179 &db_entry->key_data[db_entry->n_key_data-1]);
181 krb5_free_keyblock_contents(context, &key);
184 goto add_key_rnd_err;
188 krb5_db_free_principal(context, &krbtgt_entry, one);
194 * Change random key for a krb5_db_entry
195 * Assumes the max kvno
197 * As a side effect all old keys are nuked if keepold is false.
200 krb5_dbe_crk(context, master_key, ks_tuple, ks_tuple_count, keepold, db_entry)
201 krb5_context context;
202 krb5_keyblock * master_key;
203 krb5_key_salt_tuple * ks_tuple;
205 krb5_boolean keepold;
206 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 for (i = 0; i < key_data_count; i++) {
232 retval = krb5_dbe_create_key_data(context, db_entry);
234 cleanup_key_data(context, db_entry->n_key_data,
240 cleanup_key_data(context, key_data_count, key_data);
246 * Add random key for a krb5_db_entry
247 * Assumes the max kvno
249 * As a side effect all old keys older than the max kvno are nuked.
252 krb5_dbe_ark(context, master_key, ks_tuple, ks_tuple_count, db_entry)
253 krb5_context context;
254 krb5_keyblock * master_key;
255 krb5_key_salt_tuple * ks_tuple;
257 krb5_db_entry * db_entry;
260 krb5_key_data * key_data;
261 krb5_error_code retval;
265 /* First save the old keydata */
266 kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
267 key_data_count = db_entry->n_key_data;
268 key_data = db_entry->key_data;
269 db_entry->key_data = NULL;
270 db_entry->n_key_data = 0;
272 /* increment the kvno */
275 if (retval = add_key_rnd(context, master_key, ks_tuple,
276 ks_tuple_count, db_entry, kvno)) {
277 cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
278 db_entry->n_key_data = key_data_count;
279 db_entry->key_data = key_data;
281 /* Copy keys with key_data_kvno == kvno - 1 ( = old kvno ) */
282 for (i = 0; i < key_data_count; i++) {
283 if (key_data[i].key_data_kvno == (kvno - 1)) {
284 if (retval = krb5_dbe_create_key_data(context, db_entry)) {
285 cleanup_key_data(context, db_entry->n_key_data,
289 /* We should decrypt/re-encrypt the data to use the same mkvno*/
290 db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
291 memset(&key_data[i], 0, sizeof(krb5_key_data));
294 cleanup_key_data(context, key_data_count, key_data);
300 * Add key_data for a krb5_db_entry
301 * If passwd is NULL the assumes that the caller wants a random password.
303 static krb5_error_code
304 add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, passwd,
306 krb5_context context;
307 krb5_keyblock * master_key;
308 krb5_key_salt_tuple * ks_tuple;
311 krb5_db_entry * db_entry;
314 krb5_error_code retval;
315 krb5_keysalt key_salt;
323 for (i = 0; i < ks_tuple_count; i++) {
324 krb5_boolean similar;
329 * We could use krb5_keysalt_iterate to replace this loop, or use
330 * krb5_keysalt_is_present for the loop below, but we want to avoid
331 * circular library dependencies.
333 for (j = 0; j < i; j++) {
334 if ((retval = krb5_c_enctype_compare(context,
335 ks_tuple[i].ks_enctype,
336 ks_tuple[j].ks_enctype,
341 (ks_tuple[j].ks_salttype == ks_tuple[i].ks_salttype))
348 if (retval = krb5_dbe_create_key_data(context, db_entry))
351 /* Convert password string to key using appropriate salt */
352 switch (key_salt.type = ks_tuple[i].ks_salttype) {
353 case KRB5_KDB_SALTTYPE_ONLYREALM: {
354 krb5_data * saltdata;
355 if (retval = krb5_copy_data(context, krb5_princ_realm(context,
356 db_entry->princ), &saltdata))
359 key_salt.data = *saltdata;
360 krb5_xfree(saltdata);
363 case KRB5_KDB_SALTTYPE_NOREALM:
364 if (retval=krb5_principal2salt_norealm(context, db_entry->princ,
368 case KRB5_KDB_SALTTYPE_NORMAL:
369 if (retval = krb5_principal2salt(context, db_entry->princ,
373 case KRB5_KDB_SALTTYPE_V4:
374 key_salt.data.length = 0;
375 key_salt.data.data = 0;
377 case KRB5_KDB_SALTTYPE_AFS3: {
379 krb5_data * saltdata;
380 if (retval = krb5_copy_data(context, krb5_princ_realm(context,
381 db_entry->princ), &saltdata))
384 key_salt.data = *saltdata;
385 key_salt.data.length = -1; /*length actually used below...*/
386 krb5_xfree(saltdata);
388 /* Why do we do this? Well, the afs_mit_string_to_key needs to
389 use strlen, and the realm is not NULL terminated.... */
390 int slen = (*krb5_princ_realm(context,db_entry->princ)).length;
391 if(!(key_salt.data.data = (char *) malloc(slen+1)))
393 key_salt.data.data[slen] = 0;
394 memcpy((char *)key_salt.data.data,
395 (char *)(*krb5_princ_realm(context,db_entry->princ)).data,
397 key_salt.data.length = -1; /*length actually used below...*/
403 return(KRB5_KDB_BAD_SALTTYPE);
407 pwd.length = strlen(passwd);
409 if ((retval = krb5_c_string_to_key(context, ks_tuple[i].ks_enctype,
410 &pwd, &key_salt.data, &key))) {
411 if (key_salt.data.data)
412 free(key_salt.data.data);
416 if (key_salt.data.length == -1)
417 key_salt.data.length =
418 krb5_princ_realm(context, db_entry->princ)->length;
420 if (retval = krb5_dbekd_encrypt_key_data(context, master_key, &key,
421 (const krb5_keysalt *)&key_salt,
422 kvno, &db_entry->key_data[db_entry->n_key_data-1])) {
423 if (key_salt.data.data)
424 free(key_salt.data.data);
425 krb5_xfree(key.contents);
428 if (key_salt.data.data)
429 free(key_salt.data.data);
430 krb5_xfree(key.contents);
436 * Change password for a krb5_db_entry
437 * Assumes the max kvno
439 * As a side effect all old keys are nuked if keepold is false.
442 krb5_dbe_cpw(context, master_key, ks_tuple, ks_tuple_count, passwd,
443 new_kvno, keepold, db_entry)
444 krb5_context context;
445 krb5_keyblock * master_key;
446 krb5_key_salt_tuple * ks_tuple;
450 krb5_boolean keepold;
451 krb5_db_entry * db_entry;
454 krb5_key_data * key_data;
455 krb5_error_code retval;
459 /* First save the old keydata */
460 old_kvno = get_key_data_kvno(context, db_entry->n_key_data,
462 key_data_count = db_entry->n_key_data;
463 key_data = db_entry->key_data;
464 db_entry->key_data = NULL;
465 db_entry->n_key_data = 0;
467 /* increment the kvno. if the requested kvno is too small,
468 increment the old kvno */
469 if (new_kvno < old_kvno+1)
470 new_kvno = old_kvno+1;
472 retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count,
473 passwd, db_entry, new_kvno);
475 cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
476 db_entry->n_key_data = key_data_count;
477 db_entry->key_data = key_data;
478 } else if (keepold) {
479 for (i = 0; i < key_data_count; i++) {
480 retval = krb5_dbe_create_key_data(context, db_entry);
482 cleanup_key_data(context, db_entry->n_key_data,
488 cleanup_key_data(context, key_data_count, key_data);
494 * Add password for a krb5_db_entry
495 * Assumes the max kvno
497 * As a side effect all old keys older than the max kvno are nuked.
500 krb5_dbe_apw(context, master_key, ks_tuple, ks_tuple_count, passwd, db_entry)
501 krb5_context context;
502 krb5_keyblock * master_key;
503 krb5_key_salt_tuple * ks_tuple;
506 krb5_db_entry * db_entry;
509 krb5_key_data * key_data;
510 krb5_error_code retval;
511 int old_kvno, new_kvno;
514 /* First save the old keydata */
515 old_kvno = get_key_data_kvno(context, db_entry->n_key_data,
517 key_data_count = db_entry->n_key_data;
518 key_data = db_entry->key_data;
519 db_entry->key_data = NULL;
520 db_entry->n_key_data = 0;
522 /* increment the kvno */
523 new_kvno = old_kvno+1;
525 if (retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count,
526 passwd, db_entry, new_kvno)) {
527 cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
528 db_entry->n_key_data = key_data_count;
529 db_entry->key_data = key_data;
531 /* Copy keys with key_data_kvno == old_kvno */
532 for (i = 0; i < key_data_count; i++) {
533 if (key_data[i].key_data_kvno == old_kvno) {
534 if (retval = krb5_dbe_create_key_data(context, db_entry)) {
535 cleanup_key_data(context, db_entry->n_key_data,
539 /* We should decrypt/re-encrypt the data to use the same mkvno*/
540 db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
541 memset(&key_data[i], 0, sizeof(krb5_key_data));
544 cleanup_key_data(context, key_data_count, key_data);