xref: /illumos-gate/usr/src/lib/krb5/kdb/kdb_cpw.c (revision e0d8bef656731559f2d1d5dca0077a6a66c6f8b9)
1 /*
2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * lib/kdb/kdb_cpw.c
8  *
9  * Copyright 1995 by the Massachusetts Institute of Technology.
10  * All Rights Reserved.
11  *
12  * Export of this software from the United States of America may
13  *   require a specific license from the United States Government.
14  *   It is the responsibility of any person or organization contemplating
15  *   export to obtain such a license before exporting.
16  *
17  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
18  * distribute this software and its documentation for any purpose and
19  * without fee is hereby granted, provided that the above copyright
20  * notice appear in all copies and that both that copyright notice and
21  * this permission notice appear in supporting documentation, and that
22  * the name of M.I.T. not be used in advertising or publicity pertaining
23  * to distribution of the software without specific, written prior
24  * permission.  Furthermore if you modify this software you must label
25  * your software as modified software and not distribute it in such a
26  * fashion that it might be confused with the original M.I.T. software.
27  * M.I.T. makes no representations about the suitability of
28  * this software for any purpose.  It is provided "as is" without express
29  * or implied warranty.
30  *
31  */
32 
33 /*
34  * Copyright (C) 1998 by the FundsXpress, INC.
35  *
36  * All rights reserved.
37  *
38  * Export of this software from the United States of America may require
39  * a specific license from the United States Government.  It is the
40  * responsibility of any person or organization contemplating export to
41  * obtain such a license before exporting.
42  *
43  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
44  * distribute this software and its documentation for any purpose and
45  * without fee is hereby granted, provided that the above copyright
46  * notice appear in all copies and that both that copyright notice and
47  * this permission notice appear in supporting documentation, and that
48  * the name of FundsXpress. not be used in advertising or publicity pertaining
49  * to distribution of the software without specific, written prior
50  * permission.  FundsXpress makes no representations about the suitability of
51  * this software for any purpose.  It is provided "as is" without express
52  * or implied warranty.
53  *
54  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
55  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
56  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
57  */
58 
59 #include "k5-int.h"
60 #include "kdb.h"
61 #include <stdio.h>
62 #include <errno.h>
63 
64 static int
65 get_key_data_kvno(context, count, data)
66     krb5_context	  context;
67     int			  count;
68     krb5_key_data	* data;
69 {
70     int i, kvno;
71     /* Find last key version number */
72     for (kvno = i = 0; i < count; i++) {
73 	if (kvno < data[i].key_data_kvno) {
74 	    kvno = data[i].key_data_kvno;
75 	}
76     }
77     return(kvno);
78 }
79 
80 static void
81 cleanup_key_data(context, count, data)
82     krb5_context	  context;
83     int			  count;
84     krb5_key_data	* data;
85 {
86     int i, j;
87 
88     /* If data is NULL, count is always 0 */
89     if (data == NULL) return;
90 
91     for (i = 0; i < count; i++) {
92 	for (j = 0; j < data[i].key_data_ver; j++) {
93 	    if (data[i].key_data_length[j]) {
94 	    	krb5_db_free(context, data[i].key_data_contents[j]);
95 	    }
96 	}
97     }
98     krb5_db_free(context, data);
99 }
100 
101 static krb5_error_code
102 add_key_rnd(context, master_key, ks_tuple, ks_tuple_count, db_entry, kvno)
103     krb5_context	  context;
104     krb5_keyblock       * master_key;
105     krb5_key_salt_tuple	* ks_tuple;
106     int			  ks_tuple_count;
107     krb5_db_entry	* db_entry;
108     int			  kvno;
109 {
110     krb5_principal	  krbtgt_princ;
111     krb5_keyblock	  key;
112     krb5_db_entry	  krbtgt_entry;
113     krb5_boolean	  more;
114     int			  max_kvno, one, i, j, k;
115     krb5_error_code	  retval;
116     krb5_key_data         tmp_key_data;
117     krb5_key_data        *tptr;
118 
119     memset( &tmp_key_data, 0, sizeof(tmp_key_data));
120 
121 
122     retval = krb5_build_principal_ext(context, &krbtgt_princ,
123 				      db_entry->princ->realm.length,
124 				      db_entry->princ->realm.data,
125 				      KRB5_TGS_NAME_SIZE,
126 				      KRB5_TGS_NAME,
127 				      db_entry->princ->realm.length,
128 				      db_entry->princ->realm.data,
129 				      0);
130     if (retval)
131 	return retval;
132 
133     /* Get tgt from database */
134     retval = krb5_db_get_principal(context, krbtgt_princ, &krbtgt_entry,
135 				   &one, &more);
136     krb5_free_principal(context, krbtgt_princ); /* don't need it anymore */
137     if (retval)
138 	return(retval);
139     if ((one > 1) || (more)) {
140 	krb5_db_free_principal(context, &krbtgt_entry, one);
141 	return KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
142     }
143     if (!one)
144 	return KRB5_KDB_NOENTRY;
145 
146     /* Get max kvno */
147     for (max_kvno = j = 0; j < krbtgt_entry.n_key_data; j++) {
148 	 if (max_kvno < krbtgt_entry.key_data[j].key_data_kvno) {
149 	     max_kvno = krbtgt_entry.key_data[j].key_data_kvno;
150 	}
151     }
152 
153     for (i = 0; i < ks_tuple_count; i++) {
154 	krb5_boolean similar;
155 
156 	similar = 0;
157 
158 	/*
159 	 * We could use krb5_keysalt_iterate to replace this loop, or use
160 	 * krb5_keysalt_is_present for the loop below, but we want to avoid
161 	 * circular library dependencies.
162 	 */
163 	for (j = 0; j < i; j++) {
164 	    if ((retval = krb5_c_enctype_compare(context,
165 						 ks_tuple[i].ks_enctype,
166 						 ks_tuple[j].ks_enctype,
167 						 &similar)))
168 		return(retval);
169 
170 	    if (similar)
171 		break;
172 	}
173 
174 	if (similar)
175 	    continue;
176 
177         if ((retval = krb5_dbe_create_key_data(context, db_entry)))
178 	    goto add_key_rnd_err;
179 
180 	/* there used to be code here to extract the old key, and derive
181 	   a new key from it.  Now that there's a unified prng, that isn't
182 	   necessary. */
183 
184 	/* make new key */
185 	if ((retval = krb5_c_make_random_key(context, ks_tuple[i].ks_enctype,
186 					     &key)))
187 	    goto add_key_rnd_err;
188 
189 
190 	/* db library will free this. Since, its a so, it could actually be using different memory management
191 	   function. So, its better if the memory is allocated by the db's malloc. So, a temporary memory is used
192 	   here which will later be copied to the db_entry */
193     	retval = krb5_dbekd_encrypt_key_data(context, master_key,
194 					     &key, NULL, kvno,
195 					     &tmp_key_data);
196 
197 	krb5_free_keyblock_contents(context, &key);
198 	if( retval )
199 	    goto add_key_rnd_err;
200 
201 	tptr = &db_entry->key_data[db_entry->n_key_data-1];
202 
203 	tptr->key_data_ver = tmp_key_data.key_data_ver;
204 	tptr->key_data_kvno = tmp_key_data.key_data_kvno;
205 
206 	for( k = 0; k < tmp_key_data.key_data_ver; k++ )
207 	{
208 	    tptr->key_data_type[k] = tmp_key_data.key_data_type[k];
209 	    tptr->key_data_length[k] = tmp_key_data.key_data_length[k];
210 	    if( tmp_key_data.key_data_contents[k] )
211 	    {
212 		tptr->key_data_contents[k] = krb5_db_alloc(context, NULL, tmp_key_data.key_data_length[k]);
213 		if( tptr->key_data_contents[k] == NULL )
214 		{
215 		    cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
216 		    db_entry->key_data = NULL;
217 		    db_entry->n_key_data = 0;
218 		    retval = ENOMEM;
219 		    goto add_key_rnd_err;
220 		}
221 		memcpy( tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
222 
223 		memset( tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
224 		free( tmp_key_data.key_data_contents[k] );
225 		tmp_key_data.key_data_contents[k] = NULL;
226 	    }
227 	}
228 
229     }
230 
231 add_key_rnd_err:
232     krb5_db_free_principal(context, &krbtgt_entry, one);
233 
234     for( i = 0; i < tmp_key_data.key_data_ver; i++ )
235     {
236 	if( tmp_key_data.key_data_contents[i] )
237 	{
238 	    memset( tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]);
239 	    free( tmp_key_data.key_data_contents[i] );
240 	}
241     }
242     return(retval);
243 }
244 
245 /*
246  * Change random key for a krb5_db_entry
247  * Assumes the max kvno
248  *
249  * As a side effect all old keys are nuked if keepold is false.
250  */
251 krb5_error_code
252 krb5_dbe_crk(context, master_key, ks_tuple, ks_tuple_count, keepold, db_entry)
253     krb5_context	  context;
254     krb5_keyblock       * master_key;
255     krb5_key_salt_tuple	* ks_tuple;
256     int			  ks_tuple_count;
257     krb5_boolean	  keepold;
258     krb5_db_entry	* db_entry;
259 {
260     int 		  key_data_count;
261     int			  n_new_key_data;
262     krb5_key_data 	* key_data;
263     krb5_error_code	  retval;
264     int			  kvno;
265     int			  i;
266 
267     /* First save the old keydata */
268     kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
269     key_data_count = db_entry->n_key_data;
270     key_data = db_entry->key_data;
271     db_entry->key_data = NULL;
272     db_entry->n_key_data = 0;
273 
274     /* increment the kvno */
275     kvno++;
276 
277     retval = add_key_rnd(context, master_key, ks_tuple,
278 			 ks_tuple_count, db_entry, kvno);
279     if (retval) {
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;
283     } else if (keepold) {
284 	n_new_key_data = db_entry->n_key_data;
285 	for (i = 0; i < key_data_count; i++) {
286 	    retval = krb5_dbe_create_key_data(context, db_entry);
287 	    if (retval) {
288 		cleanup_key_data(context, db_entry->n_key_data,
289 				 db_entry->key_data);
290 		break;
291 	    }
292 	    db_entry->key_data[i+n_new_key_data] = key_data[i];
293 	    memset(&key_data[i], 0, sizeof(krb5_key_data));
294 	}
295 	krb5_db_free(context, key_data); /* we moved the cotents to new memory. But, the original block which contained the data */
296     } else {
297 	cleanup_key_data(context, key_data_count, key_data);
298     }
299     return(retval);
300 }
301 
302 /*
303  * Add random key for a krb5_db_entry
304  * Assumes the max kvno
305  *
306  * As a side effect all old keys older than the max kvno are nuked.
307  */
308 krb5_error_code
309 krb5_dbe_ark(context, master_key, ks_tuple, ks_tuple_count, db_entry)
310     krb5_context	  context;
311     krb5_keyblock       * master_key;
312     krb5_key_salt_tuple	* ks_tuple;
313     int			  ks_tuple_count;
314     krb5_db_entry	* db_entry;
315 {
316     int 		  key_data_count;
317     krb5_key_data 	* key_data;
318     krb5_error_code	  retval;
319     int			  kvno;
320     int			  i;
321 
322     /* First save the old keydata */
323     kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
324     key_data_count = db_entry->n_key_data;
325     key_data = db_entry->key_data;
326     db_entry->key_data = NULL;
327     db_entry->n_key_data = 0;
328 
329     /* increment the kvno */
330     kvno++;
331 
332     if ((retval = add_key_rnd(context, master_key, ks_tuple,
333 			     ks_tuple_count, db_entry, kvno))) {
334 	cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
335 	db_entry->n_key_data = key_data_count;
336 	db_entry->key_data = key_data;
337     } else {
338 	/* Copy keys with key_data_kvno == kvno - 1 ( = old kvno ) */
339 	for (i = 0; i < key_data_count; i++) {
340 	    if (key_data[i].key_data_kvno == (kvno - 1)) {
341 		if ((retval = krb5_dbe_create_key_data(context, db_entry))) {
342 		    cleanup_key_data(context, db_entry->n_key_data,
343 				     db_entry->key_data);
344 		    break;
345 		}
346 		/* We should decrypt/re-encrypt the data to use the same mkvno*/
347 		db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
348 		memset(&key_data[i], 0, sizeof(krb5_key_data));
349 	    }
350 	}
351 	cleanup_key_data(context, key_data_count, key_data);
352     }
353     return(retval);
354 }
355 
356 /*
357  * Add key_data for a krb5_db_entry
358  * If passwd is NULL the assumes that the caller wants a random password.
359  */
360 static krb5_error_code
361 add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, passwd,
362 	    db_entry, kvno)
363     krb5_context	  context;
364     krb5_keyblock       * master_key;
365     krb5_key_salt_tuple	* ks_tuple;
366     int			  ks_tuple_count;
367     char 		* passwd;
368     krb5_db_entry	* db_entry;
369     int			  kvno;
370 {
371     krb5_error_code	  retval;
372     krb5_keysalt	  key_salt;
373     krb5_keyblock	  key;
374     krb5_data	  	  pwd;
375     int			  i, j, k;
376     krb5_key_data         tmp_key_data;
377     krb5_key_data        *tptr;
378 
379     memset( &tmp_key_data, 0, sizeof(tmp_key_data));
380 
381     retval = 0;
382 
383     for (i = 0; i < ks_tuple_count; i++) {
384 	krb5_boolean similar;
385 
386 	similar = 0;
387 
388 	/*
389 	 * We could use krb5_keysalt_iterate to replace this loop, or use
390 	 * krb5_keysalt_is_present for the loop below, but we want to avoid
391 	 * circular library dependencies.
392 	 */
393 	for (j = 0; j < i; j++) {
394 	    if ((retval = krb5_c_enctype_compare(context,
395 						 ks_tuple[i].ks_enctype,
396 						 ks_tuple[j].ks_enctype,
397 						 &similar)))
398 		return(retval);
399 
400 	    if (similar &&
401 		(ks_tuple[j].ks_salttype == ks_tuple[i].ks_salttype))
402 		break;
403 	}
404 
405 	if (j < i)
406 	    continue;
407 
408 	if ((retval = krb5_dbe_create_key_data(context, db_entry)))
409 	    return(retval);
410 
411 	/* Convert password string to key using appropriate salt */
412 	switch (key_salt.type = ks_tuple[i].ks_salttype) {
413     	case KRB5_KDB_SALTTYPE_ONLYREALM: {
414             krb5_data * saltdata;
415             if ((retval = krb5_copy_data(context, krb5_princ_realm(context,
416 					      db_entry->princ), &saltdata)))
417 	 	return(retval);
418 
419 	    key_salt.data = *saltdata;
420 	    krb5_xfree(saltdata);
421 	}
422 		break;
423     	case KRB5_KDB_SALTTYPE_NOREALM:
424             if ((retval=krb5_principal2salt_norealm(context, db_entry->princ,
425 						    &key_salt.data)))
426 		return(retval);
427             break;
428 	case KRB5_KDB_SALTTYPE_NORMAL:
429             if ((retval = krb5_principal2salt(context, db_entry->princ,
430 					      &key_salt.data)))
431 		return(retval);
432             break;
433     	case KRB5_KDB_SALTTYPE_V4:
434             key_salt.data.length = 0;
435             key_salt.data.data = 0;
436             break;
437     	case KRB5_KDB_SALTTYPE_AFS3: {
438 #if 0
439             krb5_data * saltdata;
440             if (retval = krb5_copy_data(context, krb5_princ_realm(context,
441 					db_entry->princ), &saltdata))
442 	 	return(retval);
443 
444 	    key_salt.data = *saltdata;
445 	    key_salt.data.length = SALT_TYPE_AFS_LENGTH; /*length actually used below...*/
446 	    krb5_xfree(saltdata);
447 #else
448 	    /* Why do we do this? Well, the afs_mit_string_to_key needs to
449 	       use strlen, and the realm is not NULL terminated.... */
450 	    unsigned int slen =
451 		(*krb5_princ_realm(context,db_entry->princ)).length;
452 	    if(!(key_salt.data.data = (char *) malloc(slen+1)))
453 	        return ENOMEM;
454 	    key_salt.data.data[slen] = 0;
455 	    memcpy((char *)key_salt.data.data,
456 		   (char *)(*krb5_princ_realm(context,db_entry->princ)).data,
457 		   slen);
458 	    key_salt.data.length = SALT_TYPE_AFS_LENGTH; /*length actually used below...*/
459 #endif
460 
461 	}
462 		break;
463 	default:
464 	    return(KRB5_KDB_BAD_SALTTYPE);
465 	}
466 
467     	pwd.data = passwd;
468     	pwd.length = strlen(passwd);
469 
470 	/* Solaris Kerberos */
471 	memset(&key, 0, sizeof (krb5_keyblock));
472 
473 	/* AFS string to key will happen here */
474 	if ((retval = krb5_c_string_to_key(context, ks_tuple[i].ks_enctype,
475 					   &pwd, &key_salt.data, &key))) {
476 	     if (key_salt.data.data)
477 		  free(key_salt.data.data);
478 	     return(retval);
479 	}
480 
481 	if (key_salt.data.length == SALT_TYPE_AFS_LENGTH)
482 	    key_salt.data.length =
483 	      krb5_princ_realm(context, db_entry->princ)->length;
484 
485 	/* memory allocation to be done by db. So, use temporary block and later copy
486 	   it to the memory allocated by db */
487 	retval = krb5_dbekd_encrypt_key_data(context, master_key, &key,
488 					     (const krb5_keysalt *)&key_salt,
489 					     kvno, &tmp_key_data);
490 	if (key_salt.data.data)
491 	    free(key_salt.data.data);
492 
493 	/* Solaris Kerberos */
494 	krb5_free_keyblock_contents(context, &key);
495 
496 	if( retval )
497 	    return retval;
498 
499 	tptr = &db_entry->key_data[db_entry->n_key_data-1];
500 
501 	tptr->key_data_ver = tmp_key_data.key_data_ver;
502 	tptr->key_data_kvno = tmp_key_data.key_data_kvno;
503 
504 	for( k = 0; k < tmp_key_data.key_data_ver; k++ )
505 	{
506 	    tptr->key_data_type[k] = tmp_key_data.key_data_type[k];
507 	    tptr->key_data_length[k] = tmp_key_data.key_data_length[k];
508 	    if( tmp_key_data.key_data_contents[k] )
509 	    {
510 		tptr->key_data_contents[k] = krb5_db_alloc(context, NULL, tmp_key_data.key_data_length[k]);
511 		if( tptr->key_data_contents[k] == NULL )
512 		{
513 		    cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
514 		    db_entry->key_data = NULL;
515 		    db_entry->n_key_data = 0;
516 		    retval = ENOMEM;
517 		    goto add_key_pwd_err;
518 		}
519 		memcpy( tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
520 
521 		memset( tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
522 		free( tmp_key_data.key_data_contents[k] );
523 		tmp_key_data.key_data_contents[k] = NULL;
524 	    }
525 	}
526     }
527  add_key_pwd_err:
528     for( i = 0; i < tmp_key_data.key_data_ver; i++ )
529     {
530 	if( tmp_key_data.key_data_contents[i] )
531 	{
532 	    memset( tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]);
533 	    free( tmp_key_data.key_data_contents[i] );
534 	}
535     }
536 
537     return(retval);
538 }
539 
540 /*
541  * Change password for a krb5_db_entry
542  * Assumes the max kvno
543  *
544  * As a side effect all old keys are nuked if keepold is false.
545  */
546 krb5_error_code
547 krb5_dbe_def_cpw(context, master_key, ks_tuple, ks_tuple_count, passwd,
548 	     new_kvno, keepold, db_entry)
549     krb5_context	  context;
550     krb5_keyblock       * master_key;
551     krb5_key_salt_tuple	* ks_tuple;
552     int			  ks_tuple_count;
553     char 		* passwd;
554     int			  new_kvno;
555     krb5_boolean	  keepold;
556     krb5_db_entry	* db_entry;
557 {
558     int 		  key_data_count;
559     int			  n_new_key_data;
560     krb5_key_data 	* key_data;
561     krb5_error_code	  retval;
562     int			  old_kvno;
563     int			  i;
564 
565     /* First save the old keydata */
566     old_kvno = get_key_data_kvno(context, db_entry->n_key_data,
567 				 db_entry->key_data);
568     key_data_count = db_entry->n_key_data;
569     key_data = db_entry->key_data;
570     db_entry->key_data = NULL;
571     db_entry->n_key_data = 0;
572 
573     /* increment the kvno.  if the requested kvno is too small,
574        increment the old kvno */
575     if (new_kvno < old_kvno+1)
576        new_kvno = old_kvno+1;
577 
578     retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count,
579 			 passwd, db_entry, new_kvno);
580     if (retval) {
581 	cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
582 	db_entry->n_key_data = key_data_count;
583 	db_entry->key_data = key_data;
584     } else if (keepold) {
585 	n_new_key_data = db_entry->n_key_data;
586 	for (i = 0; i < key_data_count; i++) {
587 	    retval = krb5_dbe_create_key_data(context, db_entry);
588 	    if (retval) {
589 		cleanup_key_data(context, db_entry->n_key_data,
590 				 db_entry->key_data);
591 		break;
592 	    }
593 	    db_entry->key_data[i+n_new_key_data] = key_data[i];
594 	    memset(&key_data[i], 0, sizeof(krb5_key_data));
595 	}
596 	krb5_db_free( context, key_data );
597     } else {
598 	cleanup_key_data(context, key_data_count, key_data);
599     }
600     return(retval);
601 }
602 
603 /*
604  * Add password for a krb5_db_entry
605  * Assumes the max kvno
606  *
607  * As a side effect all old keys older than the max kvno are nuked.
608  */
609 krb5_error_code
610 krb5_dbe_apw(context, master_key, ks_tuple, ks_tuple_count, passwd, db_entry)
611     krb5_context	  context;
612     krb5_keyblock       * master_key;
613     krb5_key_salt_tuple	* ks_tuple;
614     int			  ks_tuple_count;
615     char 		* passwd;
616     krb5_db_entry	* db_entry;
617 {
618     int 		  key_data_count;
619     krb5_key_data 	* key_data;
620     krb5_error_code	  retval;
621     int			  old_kvno, new_kvno;
622     int			  i;
623 
624     /* First save the old keydata */
625     old_kvno = get_key_data_kvno(context, db_entry->n_key_data,
626 				 db_entry->key_data);
627     key_data_count = db_entry->n_key_data;
628     key_data = db_entry->key_data;
629     db_entry->key_data = NULL;
630     db_entry->n_key_data = 0;
631 
632     /* increment the kvno */
633     new_kvno = old_kvno+1;
634 
635     if ((retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count,
636 			     passwd, db_entry, new_kvno))) {
637 	cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
638 	db_entry->n_key_data = key_data_count;
639 	db_entry->key_data = key_data;
640     } else {
641 	/* Copy keys with key_data_kvno == old_kvno */
642 	for (i = 0; i < key_data_count; i++) {
643 	    if (key_data[i].key_data_kvno == old_kvno) {
644 		if ((retval = krb5_dbe_create_key_data(context, db_entry))) {
645 		    cleanup_key_data(context, db_entry->n_key_data,
646 				     db_entry->key_data);
647 		    break;
648 		}
649 		/* We should decrypt/re-encrypt the data to use the same mkvno*/
650 		db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
651 		memset(&key_data[i], 0, sizeof(krb5_key_data));
652 	    }
653 	}
654 	cleanup_key_data(context, key_data_count, key_data);
655     }
656     return(retval);
657 }
658 
659 
660