xref: /illumos-gate/usr/src/lib/krb5/kdb/kdb_cpw.c (revision 159d09a2)
17c478bd9Sstevel@tonic-gate /*
2*159d09a2SMark Phalan  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*
77c478bd9Sstevel@tonic-gate  * lib/kdb/kdb_cpw.c
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * Copyright 1995 by the Massachusetts Institute of Technology.
107c478bd9Sstevel@tonic-gate  * All Rights Reserved.
117c478bd9Sstevel@tonic-gate  *
127c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may
137c478bd9Sstevel@tonic-gate  *   require a specific license from the United States Government.
147c478bd9Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
157c478bd9Sstevel@tonic-gate  *   export to obtain such a license before exporting.
167c478bd9Sstevel@tonic-gate  *
177c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
187c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
197c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
207c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
217c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
227c478bd9Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
237c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
247c478bd9Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
257c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
267c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
277c478bd9Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
287c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
297c478bd9Sstevel@tonic-gate  * or implied warranty.
307c478bd9Sstevel@tonic-gate  *
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate /*
347c478bd9Sstevel@tonic-gate  * Copyright (C) 1998 by the FundsXpress, INC.
357c478bd9Sstevel@tonic-gate  *
367c478bd9Sstevel@tonic-gate  * All rights reserved.
377c478bd9Sstevel@tonic-gate  *
387c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may require
397c478bd9Sstevel@tonic-gate  * a specific license from the United States Government.  It is the
407c478bd9Sstevel@tonic-gate  * responsibility of any person or organization contemplating export to
417c478bd9Sstevel@tonic-gate  * obtain such a license before exporting.
427c478bd9Sstevel@tonic-gate  *
437c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
447c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
457c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
467c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
477c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
487c478bd9Sstevel@tonic-gate  * the name of FundsXpress. not be used in advertising or publicity pertaining
497c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
507c478bd9Sstevel@tonic-gate  * permission.  FundsXpress makes no representations about the suitability of
517c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
527c478bd9Sstevel@tonic-gate  * or implied warranty.
537c478bd9Sstevel@tonic-gate  *
547c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
557c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
567c478bd9Sstevel@tonic-gate  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
577c478bd9Sstevel@tonic-gate  */
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate #include "k5-int.h"
60*159d09a2SMark Phalan #include "kdb.h"
617c478bd9Sstevel@tonic-gate #include <stdio.h>
627c478bd9Sstevel@tonic-gate #include <errno.h>
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate static int
get_key_data_kvno(context,count,data)657c478bd9Sstevel@tonic-gate get_key_data_kvno(context, count, data)
667c478bd9Sstevel@tonic-gate     krb5_context	  context;
677c478bd9Sstevel@tonic-gate     int			  count;
687c478bd9Sstevel@tonic-gate     krb5_key_data	* data;
697c478bd9Sstevel@tonic-gate {
707c478bd9Sstevel@tonic-gate     int i, kvno;
717c478bd9Sstevel@tonic-gate     /* Find last key version number */
727c478bd9Sstevel@tonic-gate     for (kvno = i = 0; i < count; i++) {
737c478bd9Sstevel@tonic-gate 	if (kvno < data[i].key_data_kvno) {
747c478bd9Sstevel@tonic-gate 	    kvno = data[i].key_data_kvno;
757c478bd9Sstevel@tonic-gate 	}
767c478bd9Sstevel@tonic-gate     }
777c478bd9Sstevel@tonic-gate     return(kvno);
787c478bd9Sstevel@tonic-gate }
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate static void
cleanup_key_data(context,count,data)817c478bd9Sstevel@tonic-gate cleanup_key_data(context, count, data)
827c478bd9Sstevel@tonic-gate     krb5_context	  context;
837c478bd9Sstevel@tonic-gate     int			  count;
847c478bd9Sstevel@tonic-gate     krb5_key_data	* data;
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate     int i, j;
877c478bd9Sstevel@tonic-gate 
8856a424ccSmp     /* If data is NULL, count is always 0 */
8956a424ccSmp     if (data == NULL) return;
9056a424ccSmp 
917c478bd9Sstevel@tonic-gate     for (i = 0; i < count; i++) {
927c478bd9Sstevel@tonic-gate 	for (j = 0; j < data[i].key_data_ver; j++) {
937c478bd9Sstevel@tonic-gate 	    if (data[i].key_data_length[j]) {
94*159d09a2SMark Phalan 	    	krb5_db_free(context, data[i].key_data_contents[j]);
957c478bd9Sstevel@tonic-gate 	    }
967c478bd9Sstevel@tonic-gate 	}
977c478bd9Sstevel@tonic-gate     }
98*159d09a2SMark Phalan     krb5_db_free(context, data);
997c478bd9Sstevel@tonic-gate }
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate static krb5_error_code
add_key_rnd(context,master_key,ks_tuple,ks_tuple_count,db_entry,kvno)1027c478bd9Sstevel@tonic-gate add_key_rnd(context, master_key, ks_tuple, ks_tuple_count, db_entry, kvno)
1037c478bd9Sstevel@tonic-gate     krb5_context	  context;
1047c478bd9Sstevel@tonic-gate     krb5_keyblock       * master_key;
1057c478bd9Sstevel@tonic-gate     krb5_key_salt_tuple	* ks_tuple;
1067c478bd9Sstevel@tonic-gate     int			  ks_tuple_count;
1077c478bd9Sstevel@tonic-gate     krb5_db_entry	* db_entry;
1087c478bd9Sstevel@tonic-gate     int			  kvno;
1097c478bd9Sstevel@tonic-gate {
1107c478bd9Sstevel@tonic-gate     krb5_principal	  krbtgt_princ;
1117c478bd9Sstevel@tonic-gate     krb5_keyblock	  key;
1127c478bd9Sstevel@tonic-gate     krb5_db_entry	  krbtgt_entry;
1137c478bd9Sstevel@tonic-gate     krb5_boolean	  more;
114*159d09a2SMark Phalan     int			  max_kvno, one, i, j, k;
1157c478bd9Sstevel@tonic-gate     krb5_error_code	  retval;
116*159d09a2SMark Phalan     krb5_key_data         tmp_key_data;
117*159d09a2SMark Phalan     krb5_key_data        *tptr;
118*159d09a2SMark Phalan 
119*159d09a2SMark Phalan     memset( &tmp_key_data, 0, sizeof(tmp_key_data));
120*159d09a2SMark Phalan 
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate     retval = krb5_build_principal_ext(context, &krbtgt_princ,
1237c478bd9Sstevel@tonic-gate 				      db_entry->princ->realm.length,
1247c478bd9Sstevel@tonic-gate 				      db_entry->princ->realm.data,
1257c478bd9Sstevel@tonic-gate 				      KRB5_TGS_NAME_SIZE,
1267c478bd9Sstevel@tonic-gate 				      KRB5_TGS_NAME,
1277c478bd9Sstevel@tonic-gate 				      db_entry->princ->realm.length,
1287c478bd9Sstevel@tonic-gate 				      db_entry->princ->realm.data,
1297c478bd9Sstevel@tonic-gate 				      0);
1307c478bd9Sstevel@tonic-gate     if (retval)
1317c478bd9Sstevel@tonic-gate 	return retval;
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate     /* Get tgt from database */
1347c478bd9Sstevel@tonic-gate     retval = krb5_db_get_principal(context, krbtgt_princ, &krbtgt_entry,
1357c478bd9Sstevel@tonic-gate 				   &one, &more);
1367c478bd9Sstevel@tonic-gate     krb5_free_principal(context, krbtgt_princ); /* don't need it anymore */
1377c478bd9Sstevel@tonic-gate     if (retval)
1387c478bd9Sstevel@tonic-gate 	return(retval);
1397c478bd9Sstevel@tonic-gate     if ((one > 1) || (more)) {
1407c478bd9Sstevel@tonic-gate 	krb5_db_free_principal(context, &krbtgt_entry, one);
1417c478bd9Sstevel@tonic-gate 	return KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
1427c478bd9Sstevel@tonic-gate     }
1437c478bd9Sstevel@tonic-gate     if (!one)
1447c478bd9Sstevel@tonic-gate 	return KRB5_KDB_NOENTRY;
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate     /* Get max kvno */
1477c478bd9Sstevel@tonic-gate     for (max_kvno = j = 0; j < krbtgt_entry.n_key_data; j++) {
1487c478bd9Sstevel@tonic-gate 	 if (max_kvno < krbtgt_entry.key_data[j].key_data_kvno) {
1497c478bd9Sstevel@tonic-gate 	     max_kvno = krbtgt_entry.key_data[j].key_data_kvno;
1507c478bd9Sstevel@tonic-gate 	}
1517c478bd9Sstevel@tonic-gate     }
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate     for (i = 0; i < ks_tuple_count; i++) {
1547c478bd9Sstevel@tonic-gate 	krb5_boolean similar;
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	similar = 0;
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	/*
1597c478bd9Sstevel@tonic-gate 	 * We could use krb5_keysalt_iterate to replace this loop, or use
1607c478bd9Sstevel@tonic-gate 	 * krb5_keysalt_is_present for the loop below, but we want to avoid
1617c478bd9Sstevel@tonic-gate 	 * circular library dependencies.
1627c478bd9Sstevel@tonic-gate 	 */
1637c478bd9Sstevel@tonic-gate 	for (j = 0; j < i; j++) {
1647c478bd9Sstevel@tonic-gate 	    if ((retval = krb5_c_enctype_compare(context,
1657c478bd9Sstevel@tonic-gate 						 ks_tuple[i].ks_enctype,
1667c478bd9Sstevel@tonic-gate 						 ks_tuple[j].ks_enctype,
1677c478bd9Sstevel@tonic-gate 						 &similar)))
1687c478bd9Sstevel@tonic-gate 		return(retval);
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	    if (similar)
1717c478bd9Sstevel@tonic-gate 		break;
1727c478bd9Sstevel@tonic-gate 	}
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	if (similar)
1757c478bd9Sstevel@tonic-gate 	    continue;
1767c478bd9Sstevel@tonic-gate 
17756a424ccSmp         if ((retval = krb5_dbe_create_key_data(context, db_entry)))
1787c478bd9Sstevel@tonic-gate 	    goto add_key_rnd_err;
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	/* there used to be code here to extract the old key, and derive
1817c478bd9Sstevel@tonic-gate 	   a new key from it.  Now that there's a unified prng, that isn't
1827c478bd9Sstevel@tonic-gate 	   necessary. */
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	/* make new key */
1857c478bd9Sstevel@tonic-gate 	if ((retval = krb5_c_make_random_key(context, ks_tuple[i].ks_enctype,
1867c478bd9Sstevel@tonic-gate 					     &key)))
1877c478bd9Sstevel@tonic-gate 	    goto add_key_rnd_err;
1887c478bd9Sstevel@tonic-gate 
189*159d09a2SMark Phalan 
190*159d09a2SMark Phalan 	/* db library will free this. Since, its a so, it could actually be using different memory management
191*159d09a2SMark Phalan 	   function. So, its better if the memory is allocated by the db's malloc. So, a temporary memory is used
192*159d09a2SMark Phalan 	   here which will later be copied to the db_entry */
1937c478bd9Sstevel@tonic-gate     	retval = krb5_dbekd_encrypt_key_data(context, master_key,
1947c478bd9Sstevel@tonic-gate 					     &key, NULL, kvno,
195*159d09a2SMark Phalan 					     &tmp_key_data);
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	krb5_free_keyblock_contents(context, &key);
198*159d09a2SMark Phalan 	if( retval )
1997c478bd9Sstevel@tonic-gate 	    goto add_key_rnd_err;
200*159d09a2SMark Phalan 
201*159d09a2SMark Phalan 	tptr = &db_entry->key_data[db_entry->n_key_data-1];
202*159d09a2SMark Phalan 
203*159d09a2SMark Phalan 	tptr->key_data_ver = tmp_key_data.key_data_ver;
204*159d09a2SMark Phalan 	tptr->key_data_kvno = tmp_key_data.key_data_kvno;
205*159d09a2SMark Phalan 
206*159d09a2SMark Phalan 	for( k = 0; k < tmp_key_data.key_data_ver; k++ )
207*159d09a2SMark Phalan 	{
208*159d09a2SMark Phalan 	    tptr->key_data_type[k] = tmp_key_data.key_data_type[k];
209*159d09a2SMark Phalan 	    tptr->key_data_length[k] = tmp_key_data.key_data_length[k];
210*159d09a2SMark Phalan 	    if( tmp_key_data.key_data_contents[k] )
211*159d09a2SMark Phalan 	    {
212*159d09a2SMark Phalan 		tptr->key_data_contents[k] = krb5_db_alloc(context, NULL, tmp_key_data.key_data_length[k]);
213*159d09a2SMark Phalan 		if( tptr->key_data_contents[k] == NULL )
214*159d09a2SMark Phalan 		{
215*159d09a2SMark Phalan 		    cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
216*159d09a2SMark Phalan 		    db_entry->key_data = NULL;
217*159d09a2SMark Phalan 		    db_entry->n_key_data = 0;
218*159d09a2SMark Phalan 		    retval = ENOMEM;
219*159d09a2SMark Phalan 		    goto add_key_rnd_err;
220*159d09a2SMark Phalan 		}
221*159d09a2SMark Phalan 		memcpy( tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
222*159d09a2SMark Phalan 
223*159d09a2SMark Phalan 		memset( tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
224*159d09a2SMark Phalan 		free( tmp_key_data.key_data_contents[k] );
225*159d09a2SMark Phalan 		tmp_key_data.key_data_contents[k] = NULL;
226*159d09a2SMark Phalan 	    }
227*159d09a2SMark Phalan 	}
228*159d09a2SMark Phalan 
2297c478bd9Sstevel@tonic-gate     }
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate add_key_rnd_err:
2327c478bd9Sstevel@tonic-gate     krb5_db_free_principal(context, &krbtgt_entry, one);
2337c478bd9Sstevel@tonic-gate 
234*159d09a2SMark Phalan     for( i = 0; i < tmp_key_data.key_data_ver; i++ )
235*159d09a2SMark Phalan     {
236*159d09a2SMark Phalan 	if( tmp_key_data.key_data_contents[i] )
237*159d09a2SMark Phalan 	{
238*159d09a2SMark Phalan 	    memset( tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]);
239*159d09a2SMark Phalan 	    free( tmp_key_data.key_data_contents[i] );
240*159d09a2SMark Phalan 	}
241*159d09a2SMark Phalan     }
2427c478bd9Sstevel@tonic-gate     return(retval);
2437c478bd9Sstevel@tonic-gate }
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate /*
2467c478bd9Sstevel@tonic-gate  * Change random key for a krb5_db_entry
2477c478bd9Sstevel@tonic-gate  * Assumes the max kvno
2487c478bd9Sstevel@tonic-gate  *
2497c478bd9Sstevel@tonic-gate  * As a side effect all old keys are nuked if keepold is false.
2507c478bd9Sstevel@tonic-gate  */
2517c478bd9Sstevel@tonic-gate krb5_error_code
krb5_dbe_crk(context,master_key,ks_tuple,ks_tuple_count,keepold,db_entry)2527c478bd9Sstevel@tonic-gate krb5_dbe_crk(context, master_key, ks_tuple, ks_tuple_count, keepold, db_entry)
2537c478bd9Sstevel@tonic-gate     krb5_context	  context;
2547c478bd9Sstevel@tonic-gate     krb5_keyblock       * master_key;
2557c478bd9Sstevel@tonic-gate     krb5_key_salt_tuple	* ks_tuple;
2567c478bd9Sstevel@tonic-gate     int			  ks_tuple_count;
2577c478bd9Sstevel@tonic-gate     krb5_boolean	  keepold;
2587c478bd9Sstevel@tonic-gate     krb5_db_entry	* db_entry;
2597c478bd9Sstevel@tonic-gate {
2607c478bd9Sstevel@tonic-gate     int 		  key_data_count;
2617c478bd9Sstevel@tonic-gate     int			  n_new_key_data;
2627c478bd9Sstevel@tonic-gate     krb5_key_data 	* key_data;
2637c478bd9Sstevel@tonic-gate     krb5_error_code	  retval;
2647c478bd9Sstevel@tonic-gate     int			  kvno;
2657c478bd9Sstevel@tonic-gate     int			  i;
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate     /* First save the old keydata */
2687c478bd9Sstevel@tonic-gate     kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
2697c478bd9Sstevel@tonic-gate     key_data_count = db_entry->n_key_data;
2707c478bd9Sstevel@tonic-gate     key_data = db_entry->key_data;
2717c478bd9Sstevel@tonic-gate     db_entry->key_data = NULL;
2727c478bd9Sstevel@tonic-gate     db_entry->n_key_data = 0;
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate     /* increment the kvno */
2757c478bd9Sstevel@tonic-gate     kvno++;
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate     retval = add_key_rnd(context, master_key, ks_tuple,
2787c478bd9Sstevel@tonic-gate 			 ks_tuple_count, db_entry, kvno);
2797c478bd9Sstevel@tonic-gate     if (retval) {
2807c478bd9Sstevel@tonic-gate 	cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
2817c478bd9Sstevel@tonic-gate 	db_entry->n_key_data = key_data_count;
2827c478bd9Sstevel@tonic-gate 	db_entry->key_data = key_data;
2837c478bd9Sstevel@tonic-gate     } else if (keepold) {
2847c478bd9Sstevel@tonic-gate 	n_new_key_data = db_entry->n_key_data;
2857c478bd9Sstevel@tonic-gate 	for (i = 0; i < key_data_count; i++) {
2867c478bd9Sstevel@tonic-gate 	    retval = krb5_dbe_create_key_data(context, db_entry);
2877c478bd9Sstevel@tonic-gate 	    if (retval) {
2887c478bd9Sstevel@tonic-gate 		cleanup_key_data(context, db_entry->n_key_data,
2897c478bd9Sstevel@tonic-gate 				 db_entry->key_data);
2907c478bd9Sstevel@tonic-gate 		break;
2917c478bd9Sstevel@tonic-gate 	    }
2927c478bd9Sstevel@tonic-gate 	    db_entry->key_data[i+n_new_key_data] = key_data[i];
2937c478bd9Sstevel@tonic-gate 	    memset(&key_data[i], 0, sizeof(krb5_key_data));
2947c478bd9Sstevel@tonic-gate 	}
295*159d09a2SMark Phalan 	krb5_db_free(context, key_data); /* we moved the cotents to new memory. But, the original block which contained the data */
2967c478bd9Sstevel@tonic-gate     } else {
2977c478bd9Sstevel@tonic-gate 	cleanup_key_data(context, key_data_count, key_data);
2987c478bd9Sstevel@tonic-gate     }
2997c478bd9Sstevel@tonic-gate     return(retval);
3007c478bd9Sstevel@tonic-gate }
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate /*
3037c478bd9Sstevel@tonic-gate  * Add random key for a krb5_db_entry
3047c478bd9Sstevel@tonic-gate  * Assumes the max kvno
3057c478bd9Sstevel@tonic-gate  *
3067c478bd9Sstevel@tonic-gate  * As a side effect all old keys older than the max kvno are nuked.
3077c478bd9Sstevel@tonic-gate  */
3087c478bd9Sstevel@tonic-gate krb5_error_code
krb5_dbe_ark(context,master_key,ks_tuple,ks_tuple_count,db_entry)3097c478bd9Sstevel@tonic-gate krb5_dbe_ark(context, master_key, ks_tuple, ks_tuple_count, db_entry)
3107c478bd9Sstevel@tonic-gate     krb5_context	  context;
3117c478bd9Sstevel@tonic-gate     krb5_keyblock       * master_key;
3127c478bd9Sstevel@tonic-gate     krb5_key_salt_tuple	* ks_tuple;
3137c478bd9Sstevel@tonic-gate     int			  ks_tuple_count;
3147c478bd9Sstevel@tonic-gate     krb5_db_entry	* db_entry;
3157c478bd9Sstevel@tonic-gate {
3167c478bd9Sstevel@tonic-gate     int 		  key_data_count;
3177c478bd9Sstevel@tonic-gate     krb5_key_data 	* key_data;
3187c478bd9Sstevel@tonic-gate     krb5_error_code	  retval;
3197c478bd9Sstevel@tonic-gate     int			  kvno;
3207c478bd9Sstevel@tonic-gate     int			  i;
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate     /* First save the old keydata */
3237c478bd9Sstevel@tonic-gate     kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
3247c478bd9Sstevel@tonic-gate     key_data_count = db_entry->n_key_data;
3257c478bd9Sstevel@tonic-gate     key_data = db_entry->key_data;
3267c478bd9Sstevel@tonic-gate     db_entry->key_data = NULL;
3277c478bd9Sstevel@tonic-gate     db_entry->n_key_data = 0;
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate     /* increment the kvno */
3307c478bd9Sstevel@tonic-gate     kvno++;
3317c478bd9Sstevel@tonic-gate 
33256a424ccSmp     if ((retval = add_key_rnd(context, master_key, ks_tuple,
33356a424ccSmp 			     ks_tuple_count, db_entry, kvno))) {
3347c478bd9Sstevel@tonic-gate 	cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
3357c478bd9Sstevel@tonic-gate 	db_entry->n_key_data = key_data_count;
3367c478bd9Sstevel@tonic-gate 	db_entry->key_data = key_data;
3377c478bd9Sstevel@tonic-gate     } else {
3387c478bd9Sstevel@tonic-gate 	/* Copy keys with key_data_kvno == kvno - 1 ( = old kvno ) */
3397c478bd9Sstevel@tonic-gate 	for (i = 0; i < key_data_count; i++) {
3407c478bd9Sstevel@tonic-gate 	    if (key_data[i].key_data_kvno == (kvno - 1)) {
34156a424ccSmp 		if ((retval = krb5_dbe_create_key_data(context, db_entry))) {
3427c478bd9Sstevel@tonic-gate 		    cleanup_key_data(context, db_entry->n_key_data,
3437c478bd9Sstevel@tonic-gate 				     db_entry->key_data);
3447c478bd9Sstevel@tonic-gate 		    break;
3457c478bd9Sstevel@tonic-gate 		}
3467c478bd9Sstevel@tonic-gate 		/* We should decrypt/re-encrypt the data to use the same mkvno*/
3477c478bd9Sstevel@tonic-gate 		db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
3487c478bd9Sstevel@tonic-gate 		memset(&key_data[i], 0, sizeof(krb5_key_data));
3497c478bd9Sstevel@tonic-gate 	    }
3507c478bd9Sstevel@tonic-gate 	}
3517c478bd9Sstevel@tonic-gate 	cleanup_key_data(context, key_data_count, key_data);
3527c478bd9Sstevel@tonic-gate     }
3537c478bd9Sstevel@tonic-gate     return(retval);
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate /*
3577c478bd9Sstevel@tonic-gate  * Add key_data for a krb5_db_entry
3587c478bd9Sstevel@tonic-gate  * If passwd is NULL the assumes that the caller wants a random password.
3597c478bd9Sstevel@tonic-gate  */
3607c478bd9Sstevel@tonic-gate static krb5_error_code
add_key_pwd(context,master_key,ks_tuple,ks_tuple_count,passwd,db_entry,kvno)3617c478bd9Sstevel@tonic-gate add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, passwd,
3627c478bd9Sstevel@tonic-gate 	    db_entry, kvno)
3637c478bd9Sstevel@tonic-gate     krb5_context	  context;
3647c478bd9Sstevel@tonic-gate     krb5_keyblock       * master_key;
3657c478bd9Sstevel@tonic-gate     krb5_key_salt_tuple	* ks_tuple;
3667c478bd9Sstevel@tonic-gate     int			  ks_tuple_count;
3677c478bd9Sstevel@tonic-gate     char 		* passwd;
3687c478bd9Sstevel@tonic-gate     krb5_db_entry	* db_entry;
3697c478bd9Sstevel@tonic-gate     int			  kvno;
3707c478bd9Sstevel@tonic-gate {
3717c478bd9Sstevel@tonic-gate     krb5_error_code	  retval;
3727c478bd9Sstevel@tonic-gate     krb5_keysalt	  key_salt;
3737c478bd9Sstevel@tonic-gate     krb5_keyblock	  key;
3747c478bd9Sstevel@tonic-gate     krb5_data	  	  pwd;
375*159d09a2SMark Phalan     int			  i, j, k;
376*159d09a2SMark Phalan     krb5_key_data         tmp_key_data;
377*159d09a2SMark Phalan     krb5_key_data        *tptr;
378*159d09a2SMark Phalan 
379*159d09a2SMark Phalan     memset( &tmp_key_data, 0, sizeof(tmp_key_data));
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate     retval = 0;
38256a424ccSmp 
3837c478bd9Sstevel@tonic-gate     for (i = 0; i < ks_tuple_count; i++) {
3847c478bd9Sstevel@tonic-gate 	krb5_boolean similar;
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	similar = 0;
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	/*
3897c478bd9Sstevel@tonic-gate 	 * We could use krb5_keysalt_iterate to replace this loop, or use
3907c478bd9Sstevel@tonic-gate 	 * krb5_keysalt_is_present for the loop below, but we want to avoid
3917c478bd9Sstevel@tonic-gate 	 * circular library dependencies.
3927c478bd9Sstevel@tonic-gate 	 */
3937c478bd9Sstevel@tonic-gate 	for (j = 0; j < i; j++) {
3947c478bd9Sstevel@tonic-gate 	    if ((retval = krb5_c_enctype_compare(context,
3957c478bd9Sstevel@tonic-gate 						 ks_tuple[i].ks_enctype,
3967c478bd9Sstevel@tonic-gate 						 ks_tuple[j].ks_enctype,
3977c478bd9Sstevel@tonic-gate 						 &similar)))
3987c478bd9Sstevel@tonic-gate 		return(retval);
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	    if (similar &&
4017c478bd9Sstevel@tonic-gate 		(ks_tuple[j].ks_salttype == ks_tuple[i].ks_salttype))
4027c478bd9Sstevel@tonic-gate 		break;
4037c478bd9Sstevel@tonic-gate 	}
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	if (j < i)
4067c478bd9Sstevel@tonic-gate 	    continue;
4077c478bd9Sstevel@tonic-gate 
40856a424ccSmp 	if ((retval = krb5_dbe_create_key_data(context, db_entry)))
4097c478bd9Sstevel@tonic-gate 	    return(retval);
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	/* Convert password string to key using appropriate salt */
4127c478bd9Sstevel@tonic-gate 	switch (key_salt.type = ks_tuple[i].ks_salttype) {
4137c478bd9Sstevel@tonic-gate     	case KRB5_KDB_SALTTYPE_ONLYREALM: {
4147c478bd9Sstevel@tonic-gate             krb5_data * saltdata;
41556a424ccSmp             if ((retval = krb5_copy_data(context, krb5_princ_realm(context,
41656a424ccSmp 					      db_entry->princ), &saltdata)))
4177c478bd9Sstevel@tonic-gate 	 	return(retval);
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	    key_salt.data = *saltdata;
4207c478bd9Sstevel@tonic-gate 	    krb5_xfree(saltdata);
4217c478bd9Sstevel@tonic-gate 	}
4227c478bd9Sstevel@tonic-gate 		break;
4237c478bd9Sstevel@tonic-gate     	case KRB5_KDB_SALTTYPE_NOREALM:
42456a424ccSmp             if ((retval=krb5_principal2salt_norealm(context, db_entry->princ,
42556a424ccSmp 						    &key_salt.data)))
4267c478bd9Sstevel@tonic-gate 		return(retval);
4277c478bd9Sstevel@tonic-gate             break;
4287c478bd9Sstevel@tonic-gate 	case KRB5_KDB_SALTTYPE_NORMAL:
42956a424ccSmp             if ((retval = krb5_principal2salt(context, db_entry->princ,
43056a424ccSmp 					      &key_salt.data)))
4317c478bd9Sstevel@tonic-gate 		return(retval);
4327c478bd9Sstevel@tonic-gate             break;
4337c478bd9Sstevel@tonic-gate     	case KRB5_KDB_SALTTYPE_V4:
4347c478bd9Sstevel@tonic-gate             key_salt.data.length = 0;
4357c478bd9Sstevel@tonic-gate             key_salt.data.data = 0;
4367c478bd9Sstevel@tonic-gate             break;
4377c478bd9Sstevel@tonic-gate     	case KRB5_KDB_SALTTYPE_AFS3: {
4387c478bd9Sstevel@tonic-gate #if 0
4397c478bd9Sstevel@tonic-gate             krb5_data * saltdata;
4407c478bd9Sstevel@tonic-gate             if (retval = krb5_copy_data(context, krb5_princ_realm(context,
4417c478bd9Sstevel@tonic-gate 					db_entry->princ), &saltdata))
4427c478bd9Sstevel@tonic-gate 	 	return(retval);
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	    key_salt.data = *saltdata;
44556a424ccSmp 	    key_salt.data.length = SALT_TYPE_AFS_LENGTH; /*length actually used below...*/
4467c478bd9Sstevel@tonic-gate 	    krb5_xfree(saltdata);
4477c478bd9Sstevel@tonic-gate #else
4487c478bd9Sstevel@tonic-gate 	    /* Why do we do this? Well, the afs_mit_string_to_key needs to
4497c478bd9Sstevel@tonic-gate 	       use strlen, and the realm is not NULL terminated.... */
45056a424ccSmp 	    unsigned int slen =
45156a424ccSmp 		(*krb5_princ_realm(context,db_entry->princ)).length;
4527c478bd9Sstevel@tonic-gate 	    if(!(key_salt.data.data = (char *) malloc(slen+1)))
4537c478bd9Sstevel@tonic-gate 	        return ENOMEM;
4547c478bd9Sstevel@tonic-gate 	    key_salt.data.data[slen] = 0;
4557c478bd9Sstevel@tonic-gate 	    memcpy((char *)key_salt.data.data,
4567c478bd9Sstevel@tonic-gate 		   (char *)(*krb5_princ_realm(context,db_entry->princ)).data,
4577c478bd9Sstevel@tonic-gate 		   slen);
45856a424ccSmp 	    key_salt.data.length = SALT_TYPE_AFS_LENGTH; /*length actually used below...*/
4597c478bd9Sstevel@tonic-gate #endif
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	}
4627c478bd9Sstevel@tonic-gate 		break;
4637c478bd9Sstevel@tonic-gate 	default:
4647c478bd9Sstevel@tonic-gate 	    return(KRB5_KDB_BAD_SALTTYPE);
4657c478bd9Sstevel@tonic-gate 	}
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate     	pwd.data = passwd;
4687c478bd9Sstevel@tonic-gate     	pwd.length = strlen(passwd);
4697c478bd9Sstevel@tonic-gate 
470*159d09a2SMark Phalan 	/* Solaris Kerberos */
4717c478bd9Sstevel@tonic-gate 	memset(&key, 0, sizeof (krb5_keyblock));
472*159d09a2SMark Phalan 
473*159d09a2SMark Phalan 	/* AFS string to key will happen here */
4747c478bd9Sstevel@tonic-gate 	if ((retval = krb5_c_string_to_key(context, ks_tuple[i].ks_enctype,
4757c478bd9Sstevel@tonic-gate 					   &pwd, &key_salt.data, &key))) {
4767c478bd9Sstevel@tonic-gate 	     if (key_salt.data.data)
4777c478bd9Sstevel@tonic-gate 		  free(key_salt.data.data);
4787c478bd9Sstevel@tonic-gate 	     return(retval);
4797c478bd9Sstevel@tonic-gate 	}
4807c478bd9Sstevel@tonic-gate 
48156a424ccSmp 	if (key_salt.data.length == SALT_TYPE_AFS_LENGTH)
4827c478bd9Sstevel@tonic-gate 	    key_salt.data.length =
4837c478bd9Sstevel@tonic-gate 	      krb5_princ_realm(context, db_entry->princ)->length;
4847c478bd9Sstevel@tonic-gate 
485*159d09a2SMark Phalan 	/* memory allocation to be done by db. So, use temporary block and later copy
486*159d09a2SMark Phalan 	   it to the memory allocated by db */
487*159d09a2SMark Phalan 	retval = krb5_dbekd_encrypt_key_data(context, master_key, &key,
488*159d09a2SMark Phalan 					     (const krb5_keysalt *)&key_salt,
489*159d09a2SMark Phalan 					     kvno, &tmp_key_data);
4907c478bd9Sstevel@tonic-gate 	if (key_salt.data.data)
491*159d09a2SMark Phalan 	    free(key_salt.data.data);
4927c478bd9Sstevel@tonic-gate 
493*159d09a2SMark Phalan 	/* Solaris Kerberos */
4947c478bd9Sstevel@tonic-gate 	krb5_free_keyblock_contents(context, &key);
495*159d09a2SMark Phalan 
496*159d09a2SMark Phalan 	if( retval )
497*159d09a2SMark Phalan 	    return retval;
498*159d09a2SMark Phalan 
499*159d09a2SMark Phalan 	tptr = &db_entry->key_data[db_entry->n_key_data-1];
500*159d09a2SMark Phalan 
501*159d09a2SMark Phalan 	tptr->key_data_ver = tmp_key_data.key_data_ver;
502*159d09a2SMark Phalan 	tptr->key_data_kvno = tmp_key_data.key_data_kvno;
503*159d09a2SMark Phalan 
504*159d09a2SMark Phalan 	for( k = 0; k < tmp_key_data.key_data_ver; k++ )
505*159d09a2SMark Phalan 	{
506*159d09a2SMark Phalan 	    tptr->key_data_type[k] = tmp_key_data.key_data_type[k];
507*159d09a2SMark Phalan 	    tptr->key_data_length[k] = tmp_key_data.key_data_length[k];
508*159d09a2SMark Phalan 	    if( tmp_key_data.key_data_contents[k] )
509*159d09a2SMark Phalan 	    {
510*159d09a2SMark Phalan 		tptr->key_data_contents[k] = krb5_db_alloc(context, NULL, tmp_key_data.key_data_length[k]);
511*159d09a2SMark Phalan 		if( tptr->key_data_contents[k] == NULL )
512*159d09a2SMark Phalan 		{
513*159d09a2SMark Phalan 		    cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
514*159d09a2SMark Phalan 		    db_entry->key_data = NULL;
515*159d09a2SMark Phalan 		    db_entry->n_key_data = 0;
516*159d09a2SMark Phalan 		    retval = ENOMEM;
517*159d09a2SMark Phalan 		    goto add_key_pwd_err;
518*159d09a2SMark Phalan 		}
519*159d09a2SMark Phalan 		memcpy( tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
520*159d09a2SMark Phalan 
521*159d09a2SMark Phalan 		memset( tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
522*159d09a2SMark Phalan 		free( tmp_key_data.key_data_contents[k] );
523*159d09a2SMark Phalan 		tmp_key_data.key_data_contents[k] = NULL;
524*159d09a2SMark Phalan 	    }
525*159d09a2SMark Phalan 	}
526*159d09a2SMark Phalan     }
527*159d09a2SMark Phalan  add_key_pwd_err:
528*159d09a2SMark Phalan     for( i = 0; i < tmp_key_data.key_data_ver; i++ )
529*159d09a2SMark Phalan     {
530*159d09a2SMark Phalan 	if( tmp_key_data.key_data_contents[i] )
531*159d09a2SMark Phalan 	{
532*159d09a2SMark Phalan 	    memset( tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]);
533*159d09a2SMark Phalan 	    free( tmp_key_data.key_data_contents[i] );
534*159d09a2SMark Phalan 	}
5357c478bd9Sstevel@tonic-gate     }
536*159d09a2SMark Phalan 
5377c478bd9Sstevel@tonic-gate     return(retval);
5387c478bd9Sstevel@tonic-gate }
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate /*
5417c478bd9Sstevel@tonic-gate  * Change password for a krb5_db_entry
5427c478bd9Sstevel@tonic-gate  * Assumes the max kvno
5437c478bd9Sstevel@tonic-gate  *
5447c478bd9Sstevel@tonic-gate  * As a side effect all old keys are nuked if keepold is false.
5457c478bd9Sstevel@tonic-gate  */
5467c478bd9Sstevel@tonic-gate krb5_error_code
krb5_dbe_def_cpw(context,master_key,ks_tuple,ks_tuple_count,passwd,new_kvno,keepold,db_entry)54754925bf6Swillf krb5_dbe_def_cpw(context, master_key, ks_tuple, ks_tuple_count, passwd,
5487c478bd9Sstevel@tonic-gate 	     new_kvno, keepold, db_entry)
5497c478bd9Sstevel@tonic-gate     krb5_context	  context;
5507c478bd9Sstevel@tonic-gate     krb5_keyblock       * master_key;
5517c478bd9Sstevel@tonic-gate     krb5_key_salt_tuple	* ks_tuple;
5527c478bd9Sstevel@tonic-gate     int			  ks_tuple_count;
5537c478bd9Sstevel@tonic-gate     char 		* passwd;
5547c478bd9Sstevel@tonic-gate     int			  new_kvno;
5557c478bd9Sstevel@tonic-gate     krb5_boolean	  keepold;
5567c478bd9Sstevel@tonic-gate     krb5_db_entry	* db_entry;
5577c478bd9Sstevel@tonic-gate {
5587c478bd9Sstevel@tonic-gate     int 		  key_data_count;
5597c478bd9Sstevel@tonic-gate     int			  n_new_key_data;
5607c478bd9Sstevel@tonic-gate     krb5_key_data 	* key_data;
5617c478bd9Sstevel@tonic-gate     krb5_error_code	  retval;
5627c478bd9Sstevel@tonic-gate     int			  old_kvno;
5637c478bd9Sstevel@tonic-gate     int			  i;
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate     /* First save the old keydata */
5667c478bd9Sstevel@tonic-gate     old_kvno = get_key_data_kvno(context, db_entry->n_key_data,
5677c478bd9Sstevel@tonic-gate 				 db_entry->key_data);
5687c478bd9Sstevel@tonic-gate     key_data_count = db_entry->n_key_data;
5697c478bd9Sstevel@tonic-gate     key_data = db_entry->key_data;
5707c478bd9Sstevel@tonic-gate     db_entry->key_data = NULL;
5717c478bd9Sstevel@tonic-gate     db_entry->n_key_data = 0;
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate     /* increment the kvno.  if the requested kvno is too small,
5747c478bd9Sstevel@tonic-gate        increment the old kvno */
5757c478bd9Sstevel@tonic-gate     if (new_kvno < old_kvno+1)
5767c478bd9Sstevel@tonic-gate        new_kvno = old_kvno+1;
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate     retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count,
5797c478bd9Sstevel@tonic-gate 			 passwd, db_entry, new_kvno);
5807c478bd9Sstevel@tonic-gate     if (retval) {
5817c478bd9Sstevel@tonic-gate 	cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
5827c478bd9Sstevel@tonic-gate 	db_entry->n_key_data = key_data_count;
5837c478bd9Sstevel@tonic-gate 	db_entry->key_data = key_data;
5847c478bd9Sstevel@tonic-gate     } else if (keepold) {
5857c478bd9Sstevel@tonic-gate 	n_new_key_data = db_entry->n_key_data;
5867c478bd9Sstevel@tonic-gate 	for (i = 0; i < key_data_count; i++) {
5877c478bd9Sstevel@tonic-gate 	    retval = krb5_dbe_create_key_data(context, db_entry);
5887c478bd9Sstevel@tonic-gate 	    if (retval) {
5897c478bd9Sstevel@tonic-gate 		cleanup_key_data(context, db_entry->n_key_data,
5907c478bd9Sstevel@tonic-gate 				 db_entry->key_data);
5917c478bd9Sstevel@tonic-gate 		break;
5927c478bd9Sstevel@tonic-gate 	    }
5937c478bd9Sstevel@tonic-gate 	    db_entry->key_data[i+n_new_key_data] = key_data[i];
5947c478bd9Sstevel@tonic-gate 	    memset(&key_data[i], 0, sizeof(krb5_key_data));
5957c478bd9Sstevel@tonic-gate 	}
59654925bf6Swillf 	krb5_db_free( context, key_data );
5977c478bd9Sstevel@tonic-gate     } else {
5987c478bd9Sstevel@tonic-gate 	cleanup_key_data(context, key_data_count, key_data);
5997c478bd9Sstevel@tonic-gate     }
6007c478bd9Sstevel@tonic-gate     return(retval);
6017c478bd9Sstevel@tonic-gate }
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate /*
6047c478bd9Sstevel@tonic-gate  * Add password for a krb5_db_entry
6057c478bd9Sstevel@tonic-gate  * Assumes the max kvno
6067c478bd9Sstevel@tonic-gate  *
6077c478bd9Sstevel@tonic-gate  * As a side effect all old keys older than the max kvno are nuked.
6087c478bd9Sstevel@tonic-gate  */
6097c478bd9Sstevel@tonic-gate krb5_error_code
krb5_dbe_apw(context,master_key,ks_tuple,ks_tuple_count,passwd,db_entry)6107c478bd9Sstevel@tonic-gate krb5_dbe_apw(context, master_key, ks_tuple, ks_tuple_count, passwd, db_entry)
6117c478bd9Sstevel@tonic-gate     krb5_context	  context;
6127c478bd9Sstevel@tonic-gate     krb5_keyblock       * master_key;
6137c478bd9Sstevel@tonic-gate     krb5_key_salt_tuple	* ks_tuple;
6147c478bd9Sstevel@tonic-gate     int			  ks_tuple_count;
6157c478bd9Sstevel@tonic-gate     char 		* passwd;
6167c478bd9Sstevel@tonic-gate     krb5_db_entry	* db_entry;
6177c478bd9Sstevel@tonic-gate {
6187c478bd9Sstevel@tonic-gate     int 		  key_data_count;
6197c478bd9Sstevel@tonic-gate     krb5_key_data 	* key_data;
6207c478bd9Sstevel@tonic-gate     krb5_error_code	  retval;
6217c478bd9Sstevel@tonic-gate     int			  old_kvno, new_kvno;
6227c478bd9Sstevel@tonic-gate     int			  i;
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate     /* First save the old keydata */
6257c478bd9Sstevel@tonic-gate     old_kvno = get_key_data_kvno(context, db_entry->n_key_data,
6267c478bd9Sstevel@tonic-gate 				 db_entry->key_data);
6277c478bd9Sstevel@tonic-gate     key_data_count = db_entry->n_key_data;
6287c478bd9Sstevel@tonic-gate     key_data = db_entry->key_data;
6297c478bd9Sstevel@tonic-gate     db_entry->key_data = NULL;
6307c478bd9Sstevel@tonic-gate     db_entry->n_key_data = 0;
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate     /* increment the kvno */
6337c478bd9Sstevel@tonic-gate     new_kvno = old_kvno+1;
6347c478bd9Sstevel@tonic-gate 
63556a424ccSmp     if ((retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count,
63656a424ccSmp 			     passwd, db_entry, new_kvno))) {
6377c478bd9Sstevel@tonic-gate 	cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
6387c478bd9Sstevel@tonic-gate 	db_entry->n_key_data = key_data_count;
6397c478bd9Sstevel@tonic-gate 	db_entry->key_data = key_data;
6407c478bd9Sstevel@tonic-gate     } else {
6417c478bd9Sstevel@tonic-gate 	/* Copy keys with key_data_kvno == old_kvno */
6427c478bd9Sstevel@tonic-gate 	for (i = 0; i < key_data_count; i++) {
6437c478bd9Sstevel@tonic-gate 	    if (key_data[i].key_data_kvno == old_kvno) {
64456a424ccSmp 		if ((retval = krb5_dbe_create_key_data(context, db_entry))) {
6457c478bd9Sstevel@tonic-gate 		    cleanup_key_data(context, db_entry->n_key_data,
6467c478bd9Sstevel@tonic-gate 				     db_entry->key_data);
6477c478bd9Sstevel@tonic-gate 		    break;
6487c478bd9Sstevel@tonic-gate 		}
6497c478bd9Sstevel@tonic-gate 		/* We should decrypt/re-encrypt the data to use the same mkvno*/
6507c478bd9Sstevel@tonic-gate 		db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
6517c478bd9Sstevel@tonic-gate 		memset(&key_data[i], 0, sizeof(krb5_key_data));
6527c478bd9Sstevel@tonic-gate 	    }
6537c478bd9Sstevel@tonic-gate 	}
6547c478bd9Sstevel@tonic-gate 	cleanup_key_data(context, key_data_count, key_data);
6557c478bd9Sstevel@tonic-gate     }
6567c478bd9Sstevel@tonic-gate     return(retval);
6577c478bd9Sstevel@tonic-gate }
658*159d09a2SMark Phalan 
659*159d09a2SMark Phalan 
660