xref: /illumos-gate/usr/src/lib/krb5/kdb/kdb_cpw.c (revision 54925bf6)
17c478bd9Sstevel@tonic-gate /*
2*54925bf6Swillf  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
67c478bd9Sstevel@tonic-gate 
77c478bd9Sstevel@tonic-gate /*
87c478bd9Sstevel@tonic-gate  * lib/kdb/kdb_cpw.c
97c478bd9Sstevel@tonic-gate  *
107c478bd9Sstevel@tonic-gate  * Copyright 1995 by the Massachusetts Institute of Technology.
117c478bd9Sstevel@tonic-gate  * All Rights Reserved.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may
147c478bd9Sstevel@tonic-gate  *   require a specific license from the United States Government.
157c478bd9Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
167c478bd9Sstevel@tonic-gate  *   export to obtain such a license before exporting.
177c478bd9Sstevel@tonic-gate  *
187c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
197c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
207c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
217c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
227c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
237c478bd9Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
247c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
257c478bd9Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
267c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
277c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
287c478bd9Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
297c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
307c478bd9Sstevel@tonic-gate  * or implied warranty.
317c478bd9Sstevel@tonic-gate  *
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate /*
357c478bd9Sstevel@tonic-gate  * Copyright (C) 1998 by the FundsXpress, INC.
367c478bd9Sstevel@tonic-gate  *
377c478bd9Sstevel@tonic-gate  * All rights reserved.
387c478bd9Sstevel@tonic-gate  *
397c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may require
407c478bd9Sstevel@tonic-gate  * a specific license from the United States Government.  It is the
417c478bd9Sstevel@tonic-gate  * responsibility of any person or organization contemplating export to
427c478bd9Sstevel@tonic-gate  * obtain such a license before exporting.
437c478bd9Sstevel@tonic-gate  *
447c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
457c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
467c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
477c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
487c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
497c478bd9Sstevel@tonic-gate  * the name of FundsXpress. not be used in advertising or publicity pertaining
507c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
517c478bd9Sstevel@tonic-gate  * permission.  FundsXpress makes no representations about the suitability of
527c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
537c478bd9Sstevel@tonic-gate  * or implied warranty.
547c478bd9Sstevel@tonic-gate  *
557c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
567c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
577c478bd9Sstevel@tonic-gate  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
587c478bd9Sstevel@tonic-gate  */
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate #include "k5-int.h"
61*54925bf6Swillf #include <kdb.h>
627c478bd9Sstevel@tonic-gate #include <stdio.h>
637c478bd9Sstevel@tonic-gate #include <errno.h>
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate static int
667c478bd9Sstevel@tonic-gate get_key_data_kvno(context, count, data)
677c478bd9Sstevel@tonic-gate     krb5_context	  context;
687c478bd9Sstevel@tonic-gate     int			  count;
697c478bd9Sstevel@tonic-gate     krb5_key_data	* data;
707c478bd9Sstevel@tonic-gate {
717c478bd9Sstevel@tonic-gate     int i, kvno;
727c478bd9Sstevel@tonic-gate     /* Find last key version number */
737c478bd9Sstevel@tonic-gate     for (kvno = i = 0; i < count; i++) {
747c478bd9Sstevel@tonic-gate 	if (kvno < data[i].key_data_kvno) {
757c478bd9Sstevel@tonic-gate 	    kvno = data[i].key_data_kvno;
767c478bd9Sstevel@tonic-gate 	}
777c478bd9Sstevel@tonic-gate     }
787c478bd9Sstevel@tonic-gate     return(kvno);
797c478bd9Sstevel@tonic-gate }
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate static void
827c478bd9Sstevel@tonic-gate cleanup_key_data(context, count, data)
837c478bd9Sstevel@tonic-gate     krb5_context	  context;
847c478bd9Sstevel@tonic-gate     int			  count;
857c478bd9Sstevel@tonic-gate     krb5_key_data	* data;
867c478bd9Sstevel@tonic-gate {
877c478bd9Sstevel@tonic-gate     int i, j;
887c478bd9Sstevel@tonic-gate 
8956a424ccSmp     /* If data is NULL, count is always 0 */
9056a424ccSmp     if (data == NULL) return;
9156a424ccSmp 
927c478bd9Sstevel@tonic-gate     for (i = 0; i < count; i++) {
937c478bd9Sstevel@tonic-gate 	for (j = 0; j < data[i].key_data_ver; j++) {
947c478bd9Sstevel@tonic-gate 	    if (data[i].key_data_length[j]) {
957c478bd9Sstevel@tonic-gate 	    	free(data[i].key_data_contents[j]);
967c478bd9Sstevel@tonic-gate 	    }
977c478bd9Sstevel@tonic-gate 	}
987c478bd9Sstevel@tonic-gate     }
997c478bd9Sstevel@tonic-gate     free(data);
1007c478bd9Sstevel@tonic-gate }
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate static krb5_error_code
1037c478bd9Sstevel@tonic-gate add_key_rnd(context, master_key, ks_tuple, ks_tuple_count, db_entry, kvno)
1047c478bd9Sstevel@tonic-gate     krb5_context	  context;
1057c478bd9Sstevel@tonic-gate     krb5_keyblock       * master_key;
1067c478bd9Sstevel@tonic-gate     krb5_key_salt_tuple	* ks_tuple;
1077c478bd9Sstevel@tonic-gate     int			  ks_tuple_count;
1087c478bd9Sstevel@tonic-gate     krb5_db_entry	* db_entry;
1097c478bd9Sstevel@tonic-gate     int			  kvno;
1107c478bd9Sstevel@tonic-gate {
1117c478bd9Sstevel@tonic-gate     krb5_principal	  krbtgt_princ;
1127c478bd9Sstevel@tonic-gate     krb5_keyblock	  key;
1137c478bd9Sstevel@tonic-gate     krb5_db_entry	  krbtgt_entry;
1147c478bd9Sstevel@tonic-gate     krb5_boolean	  more;
1157c478bd9Sstevel@tonic-gate     int			  max_kvno, one, i, j;
1167c478bd9Sstevel@tonic-gate     krb5_error_code	  retval;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate     retval = krb5_build_principal_ext(context, &krbtgt_princ,
1197c478bd9Sstevel@tonic-gate 				      db_entry->princ->realm.length,
1207c478bd9Sstevel@tonic-gate 				      db_entry->princ->realm.data,
1217c478bd9Sstevel@tonic-gate 				      KRB5_TGS_NAME_SIZE,
1227c478bd9Sstevel@tonic-gate 				      KRB5_TGS_NAME,
1237c478bd9Sstevel@tonic-gate 				      db_entry->princ->realm.length,
1247c478bd9Sstevel@tonic-gate 				      db_entry->princ->realm.data,
1257c478bd9Sstevel@tonic-gate 				      0);
1267c478bd9Sstevel@tonic-gate     if (retval)
1277c478bd9Sstevel@tonic-gate 	return retval;
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate     /* Get tgt from database */
1307c478bd9Sstevel@tonic-gate     retval = krb5_db_get_principal(context, krbtgt_princ, &krbtgt_entry,
1317c478bd9Sstevel@tonic-gate 				   &one, &more);
1327c478bd9Sstevel@tonic-gate     krb5_free_principal(context, krbtgt_princ); /* don't need it anymore */
1337c478bd9Sstevel@tonic-gate     if (retval)
1347c478bd9Sstevel@tonic-gate 	return(retval);
1357c478bd9Sstevel@tonic-gate     if ((one > 1) || (more)) {
1367c478bd9Sstevel@tonic-gate 	krb5_db_free_principal(context, &krbtgt_entry, one);
1377c478bd9Sstevel@tonic-gate 	return KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
1387c478bd9Sstevel@tonic-gate     }
1397c478bd9Sstevel@tonic-gate     if (!one)
1407c478bd9Sstevel@tonic-gate 	return KRB5_KDB_NOENTRY;
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate     /* Get max kvno */
1437c478bd9Sstevel@tonic-gate     for (max_kvno = j = 0; j < krbtgt_entry.n_key_data; j++) {
1447c478bd9Sstevel@tonic-gate 	 if (max_kvno < krbtgt_entry.key_data[j].key_data_kvno) {
1457c478bd9Sstevel@tonic-gate 	     max_kvno = krbtgt_entry.key_data[j].key_data_kvno;
1467c478bd9Sstevel@tonic-gate 	}
1477c478bd9Sstevel@tonic-gate     }
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate     for (i = 0; i < ks_tuple_count; i++) {
1507c478bd9Sstevel@tonic-gate 	krb5_boolean similar;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	similar = 0;
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	/*
1557c478bd9Sstevel@tonic-gate 	 * We could use krb5_keysalt_iterate to replace this loop, or use
1567c478bd9Sstevel@tonic-gate 	 * krb5_keysalt_is_present for the loop below, but we want to avoid
1577c478bd9Sstevel@tonic-gate 	 * circular library dependencies.
1587c478bd9Sstevel@tonic-gate 	 */
1597c478bd9Sstevel@tonic-gate 	for (j = 0; j < i; j++) {
1607c478bd9Sstevel@tonic-gate 	    if ((retval = krb5_c_enctype_compare(context,
1617c478bd9Sstevel@tonic-gate 						 ks_tuple[i].ks_enctype,
1627c478bd9Sstevel@tonic-gate 						 ks_tuple[j].ks_enctype,
1637c478bd9Sstevel@tonic-gate 						 &similar)))
1647c478bd9Sstevel@tonic-gate 		return(retval);
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	    if (similar)
1677c478bd9Sstevel@tonic-gate 		break;
1687c478bd9Sstevel@tonic-gate 	}
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	if (similar)
1717c478bd9Sstevel@tonic-gate 	    continue;
1727c478bd9Sstevel@tonic-gate 
17356a424ccSmp         if ((retval = krb5_dbe_create_key_data(context, db_entry)))
1747c478bd9Sstevel@tonic-gate 	    goto add_key_rnd_err;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	/* there used to be code here to extract the old key, and derive
1777c478bd9Sstevel@tonic-gate 	   a new key from it.  Now that there's a unified prng, that isn't
1787c478bd9Sstevel@tonic-gate 	   necessary. */
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	/* make new key */
1817c478bd9Sstevel@tonic-gate 	if ((retval = krb5_c_make_random_key(context, ks_tuple[i].ks_enctype,
1827c478bd9Sstevel@tonic-gate 					     &key)))
1837c478bd9Sstevel@tonic-gate 	    goto add_key_rnd_err;
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate     	retval = krb5_dbekd_encrypt_key_data(context, master_key,
1867c478bd9Sstevel@tonic-gate 					     &key, NULL, kvno,
1877c478bd9Sstevel@tonic-gate 					     &db_entry->key_data[db_entry->n_key_data-1]);
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	krb5_free_keyblock_contents(context, &key);
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	if (retval)
1927c478bd9Sstevel@tonic-gate 	    goto add_key_rnd_err;
1937c478bd9Sstevel@tonic-gate     }
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate add_key_rnd_err:
1967c478bd9Sstevel@tonic-gate     krb5_db_free_principal(context, &krbtgt_entry, one);
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate     return(retval);
1997c478bd9Sstevel@tonic-gate }
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate /*
2027c478bd9Sstevel@tonic-gate  * Change random key for a krb5_db_entry
2037c478bd9Sstevel@tonic-gate  * Assumes the max kvno
2047c478bd9Sstevel@tonic-gate  *
2057c478bd9Sstevel@tonic-gate  * As a side effect all old keys are nuked if keepold is false.
2067c478bd9Sstevel@tonic-gate  */
2077c478bd9Sstevel@tonic-gate krb5_error_code
2087c478bd9Sstevel@tonic-gate krb5_dbe_crk(context, master_key, ks_tuple, ks_tuple_count, keepold, db_entry)
2097c478bd9Sstevel@tonic-gate     krb5_context	  context;
2107c478bd9Sstevel@tonic-gate     krb5_keyblock       * master_key;
2117c478bd9Sstevel@tonic-gate     krb5_key_salt_tuple	* ks_tuple;
2127c478bd9Sstevel@tonic-gate     int			  ks_tuple_count;
2137c478bd9Sstevel@tonic-gate     krb5_boolean	  keepold;
2147c478bd9Sstevel@tonic-gate     krb5_db_entry	* db_entry;
2157c478bd9Sstevel@tonic-gate {
2167c478bd9Sstevel@tonic-gate     int 		  key_data_count;
2177c478bd9Sstevel@tonic-gate     int			  n_new_key_data;
2187c478bd9Sstevel@tonic-gate     krb5_key_data 	* key_data;
2197c478bd9Sstevel@tonic-gate     krb5_error_code	  retval;
2207c478bd9Sstevel@tonic-gate     int			  kvno;
2217c478bd9Sstevel@tonic-gate     int			  i;
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate     /* First save the old keydata */
2247c478bd9Sstevel@tonic-gate     kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
2257c478bd9Sstevel@tonic-gate     key_data_count = db_entry->n_key_data;
2267c478bd9Sstevel@tonic-gate     key_data = db_entry->key_data;
2277c478bd9Sstevel@tonic-gate     db_entry->key_data = NULL;
2287c478bd9Sstevel@tonic-gate     db_entry->n_key_data = 0;
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate     /* increment the kvno */
2317c478bd9Sstevel@tonic-gate     kvno++;
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate     retval = add_key_rnd(context, master_key, ks_tuple,
2347c478bd9Sstevel@tonic-gate 			 ks_tuple_count, db_entry, kvno);
2357c478bd9Sstevel@tonic-gate     if (retval) {
2367c478bd9Sstevel@tonic-gate 	cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
2377c478bd9Sstevel@tonic-gate 	db_entry->n_key_data = key_data_count;
2387c478bd9Sstevel@tonic-gate 	db_entry->key_data = key_data;
2397c478bd9Sstevel@tonic-gate     } else if (keepold) {
2407c478bd9Sstevel@tonic-gate 	n_new_key_data = db_entry->n_key_data;
2417c478bd9Sstevel@tonic-gate 	for (i = 0; i < key_data_count; i++) {
2427c478bd9Sstevel@tonic-gate 	    retval = krb5_dbe_create_key_data(context, db_entry);
2437c478bd9Sstevel@tonic-gate 	    if (retval) {
2447c478bd9Sstevel@tonic-gate 		cleanup_key_data(context, db_entry->n_key_data,
2457c478bd9Sstevel@tonic-gate 				 db_entry->key_data);
2467c478bd9Sstevel@tonic-gate 		break;
2477c478bd9Sstevel@tonic-gate 	    }
2487c478bd9Sstevel@tonic-gate 	    db_entry->key_data[i+n_new_key_data] = key_data[i];
2497c478bd9Sstevel@tonic-gate 	    memset(&key_data[i], 0, sizeof(krb5_key_data));
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate     } else {
2527c478bd9Sstevel@tonic-gate 	cleanup_key_data(context, key_data_count, key_data);
2537c478bd9Sstevel@tonic-gate     }
2547c478bd9Sstevel@tonic-gate     return(retval);
2557c478bd9Sstevel@tonic-gate }
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate /*
2587c478bd9Sstevel@tonic-gate  * Add random key for a krb5_db_entry
2597c478bd9Sstevel@tonic-gate  * Assumes the max kvno
2607c478bd9Sstevel@tonic-gate  *
2617c478bd9Sstevel@tonic-gate  * As a side effect all old keys older than the max kvno are nuked.
2627c478bd9Sstevel@tonic-gate  */
2637c478bd9Sstevel@tonic-gate krb5_error_code
2647c478bd9Sstevel@tonic-gate krb5_dbe_ark(context, master_key, ks_tuple, ks_tuple_count, db_entry)
2657c478bd9Sstevel@tonic-gate     krb5_context	  context;
2667c478bd9Sstevel@tonic-gate     krb5_keyblock       * master_key;
2677c478bd9Sstevel@tonic-gate     krb5_key_salt_tuple	* ks_tuple;
2687c478bd9Sstevel@tonic-gate     int			  ks_tuple_count;
2697c478bd9Sstevel@tonic-gate     krb5_db_entry	* db_entry;
2707c478bd9Sstevel@tonic-gate {
2717c478bd9Sstevel@tonic-gate     int 		  key_data_count;
2727c478bd9Sstevel@tonic-gate     krb5_key_data 	* key_data;
2737c478bd9Sstevel@tonic-gate     krb5_error_code	  retval;
2747c478bd9Sstevel@tonic-gate     int			  kvno;
2757c478bd9Sstevel@tonic-gate     int			  i;
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate     /* First save the old keydata */
2787c478bd9Sstevel@tonic-gate     kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
2797c478bd9Sstevel@tonic-gate     key_data_count = db_entry->n_key_data;
2807c478bd9Sstevel@tonic-gate     key_data = db_entry->key_data;
2817c478bd9Sstevel@tonic-gate     db_entry->key_data = NULL;
2827c478bd9Sstevel@tonic-gate     db_entry->n_key_data = 0;
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate     /* increment the kvno */
2857c478bd9Sstevel@tonic-gate     kvno++;
2867c478bd9Sstevel@tonic-gate 
28756a424ccSmp     if ((retval = add_key_rnd(context, master_key, ks_tuple,
28856a424ccSmp 			     ks_tuple_count, db_entry, kvno))) {
2897c478bd9Sstevel@tonic-gate 	cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
2907c478bd9Sstevel@tonic-gate 	db_entry->n_key_data = key_data_count;
2917c478bd9Sstevel@tonic-gate 	db_entry->key_data = key_data;
2927c478bd9Sstevel@tonic-gate     } else {
2937c478bd9Sstevel@tonic-gate 	/* Copy keys with key_data_kvno == kvno - 1 ( = old kvno ) */
2947c478bd9Sstevel@tonic-gate 	for (i = 0; i < key_data_count; i++) {
2957c478bd9Sstevel@tonic-gate 	    if (key_data[i].key_data_kvno == (kvno - 1)) {
29656a424ccSmp 		if ((retval = krb5_dbe_create_key_data(context, db_entry))) {
2977c478bd9Sstevel@tonic-gate 		    cleanup_key_data(context, db_entry->n_key_data,
2987c478bd9Sstevel@tonic-gate 				     db_entry->key_data);
2997c478bd9Sstevel@tonic-gate 		    break;
3007c478bd9Sstevel@tonic-gate 		}
3017c478bd9Sstevel@tonic-gate 		/* We should decrypt/re-encrypt the data to use the same mkvno*/
3027c478bd9Sstevel@tonic-gate 		db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
3037c478bd9Sstevel@tonic-gate 		memset(&key_data[i], 0, sizeof(krb5_key_data));
3047c478bd9Sstevel@tonic-gate 	    }
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 	cleanup_key_data(context, key_data_count, key_data);
3077c478bd9Sstevel@tonic-gate     }
3087c478bd9Sstevel@tonic-gate     return(retval);
3097c478bd9Sstevel@tonic-gate }
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate /*
3127c478bd9Sstevel@tonic-gate  * Add key_data for a krb5_db_entry
3137c478bd9Sstevel@tonic-gate  * If passwd is NULL the assumes that the caller wants a random password.
3147c478bd9Sstevel@tonic-gate  */
3157c478bd9Sstevel@tonic-gate static krb5_error_code
3167c478bd9Sstevel@tonic-gate add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, passwd,
3177c478bd9Sstevel@tonic-gate 	    db_entry, kvno)
3187c478bd9Sstevel@tonic-gate     krb5_context	  context;
3197c478bd9Sstevel@tonic-gate     krb5_keyblock       * master_key;
3207c478bd9Sstevel@tonic-gate     krb5_key_salt_tuple	* ks_tuple;
3217c478bd9Sstevel@tonic-gate     int			  ks_tuple_count;
3227c478bd9Sstevel@tonic-gate     char 		* passwd;
3237c478bd9Sstevel@tonic-gate     krb5_db_entry	* db_entry;
3247c478bd9Sstevel@tonic-gate     int			  kvno;
3257c478bd9Sstevel@tonic-gate {
3267c478bd9Sstevel@tonic-gate     krb5_error_code	  retval;
3277c478bd9Sstevel@tonic-gate     krb5_keysalt	  key_salt;
3287c478bd9Sstevel@tonic-gate     krb5_keyblock	  key;
3297c478bd9Sstevel@tonic-gate     krb5_data	  	  pwd;
3307c478bd9Sstevel@tonic-gate     int			  i, j;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate     retval = 0;
33356a424ccSmp 
3347c478bd9Sstevel@tonic-gate     for (i = 0; i < ks_tuple_count; i++) {
3357c478bd9Sstevel@tonic-gate 	krb5_boolean similar;
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	similar = 0;
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	/*
3407c478bd9Sstevel@tonic-gate 	 * We could use krb5_keysalt_iterate to replace this loop, or use
3417c478bd9Sstevel@tonic-gate 	 * krb5_keysalt_is_present for the loop below, but we want to avoid
3427c478bd9Sstevel@tonic-gate 	 * circular library dependencies.
3437c478bd9Sstevel@tonic-gate 	 */
3447c478bd9Sstevel@tonic-gate 	for (j = 0; j < i; j++) {
3457c478bd9Sstevel@tonic-gate 	    if ((retval = krb5_c_enctype_compare(context,
3467c478bd9Sstevel@tonic-gate 						 ks_tuple[i].ks_enctype,
3477c478bd9Sstevel@tonic-gate 						 ks_tuple[j].ks_enctype,
3487c478bd9Sstevel@tonic-gate 						 &similar)))
3497c478bd9Sstevel@tonic-gate 		return(retval);
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	    if (similar &&
3527c478bd9Sstevel@tonic-gate 		(ks_tuple[j].ks_salttype == ks_tuple[i].ks_salttype))
3537c478bd9Sstevel@tonic-gate 		break;
3547c478bd9Sstevel@tonic-gate 	}
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	if (j < i)
3577c478bd9Sstevel@tonic-gate 	    continue;
3587c478bd9Sstevel@tonic-gate 
35956a424ccSmp 	if ((retval = krb5_dbe_create_key_data(context, db_entry)))
3607c478bd9Sstevel@tonic-gate 	    return(retval);
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	/* Convert password string to key using appropriate salt */
3637c478bd9Sstevel@tonic-gate 	switch (key_salt.type = ks_tuple[i].ks_salttype) {
3647c478bd9Sstevel@tonic-gate     	case KRB5_KDB_SALTTYPE_ONLYREALM: {
3657c478bd9Sstevel@tonic-gate             krb5_data * saltdata;
36656a424ccSmp             if ((retval = krb5_copy_data(context, krb5_princ_realm(context,
36756a424ccSmp 					      db_entry->princ), &saltdata)))
3687c478bd9Sstevel@tonic-gate 	 	return(retval);
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	    key_salt.data = *saltdata;
3717c478bd9Sstevel@tonic-gate 	    krb5_xfree(saltdata);
3727c478bd9Sstevel@tonic-gate 	}
3737c478bd9Sstevel@tonic-gate 		break;
3747c478bd9Sstevel@tonic-gate     	case KRB5_KDB_SALTTYPE_NOREALM:
37556a424ccSmp             if ((retval=krb5_principal2salt_norealm(context, db_entry->princ,
37656a424ccSmp 						    &key_salt.data)))
3777c478bd9Sstevel@tonic-gate 		return(retval);
3787c478bd9Sstevel@tonic-gate             break;
3797c478bd9Sstevel@tonic-gate 	case KRB5_KDB_SALTTYPE_NORMAL:
38056a424ccSmp             if ((retval = krb5_principal2salt(context, db_entry->princ,
38156a424ccSmp 					      &key_salt.data)))
3827c478bd9Sstevel@tonic-gate 		return(retval);
3837c478bd9Sstevel@tonic-gate             break;
3847c478bd9Sstevel@tonic-gate     	case KRB5_KDB_SALTTYPE_V4:
3857c478bd9Sstevel@tonic-gate             key_salt.data.length = 0;
3867c478bd9Sstevel@tonic-gate             key_salt.data.data = 0;
3877c478bd9Sstevel@tonic-gate             break;
3887c478bd9Sstevel@tonic-gate     	case KRB5_KDB_SALTTYPE_AFS3: {
3897c478bd9Sstevel@tonic-gate #if 0
3907c478bd9Sstevel@tonic-gate             krb5_data * saltdata;
3917c478bd9Sstevel@tonic-gate             if (retval = krb5_copy_data(context, krb5_princ_realm(context,
3927c478bd9Sstevel@tonic-gate 					db_entry->princ), &saltdata))
3937c478bd9Sstevel@tonic-gate 	 	return(retval);
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	    key_salt.data = *saltdata;
39656a424ccSmp 	    key_salt.data.length = SALT_TYPE_AFS_LENGTH; /*length actually used below...*/
3977c478bd9Sstevel@tonic-gate 	    krb5_xfree(saltdata);
3987c478bd9Sstevel@tonic-gate #else
3997c478bd9Sstevel@tonic-gate 	    /* Why do we do this? Well, the afs_mit_string_to_key needs to
4007c478bd9Sstevel@tonic-gate 	       use strlen, and the realm is not NULL terminated.... */
40156a424ccSmp 	    unsigned int slen =
40256a424ccSmp 		(*krb5_princ_realm(context,db_entry->princ)).length;
4037c478bd9Sstevel@tonic-gate 	    if(!(key_salt.data.data = (char *) malloc(slen+1)))
4047c478bd9Sstevel@tonic-gate 	        return ENOMEM;
4057c478bd9Sstevel@tonic-gate 	    key_salt.data.data[slen] = 0;
4067c478bd9Sstevel@tonic-gate 	    memcpy((char *)key_salt.data.data,
4077c478bd9Sstevel@tonic-gate 		   (char *)(*krb5_princ_realm(context,db_entry->princ)).data,
4087c478bd9Sstevel@tonic-gate 		   slen);
40956a424ccSmp 	    key_salt.data.length = SALT_TYPE_AFS_LENGTH; /*length actually used below...*/
4107c478bd9Sstevel@tonic-gate #endif
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	}
4137c478bd9Sstevel@tonic-gate 		break;
4147c478bd9Sstevel@tonic-gate 	default:
4157c478bd9Sstevel@tonic-gate 	    return(KRB5_KDB_BAD_SALTTYPE);
4167c478bd9Sstevel@tonic-gate 	}
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate     	pwd.data = passwd;
4197c478bd9Sstevel@tonic-gate     	pwd.length = strlen(passwd);
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	memset(&key, 0, sizeof (krb5_keyblock));
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	if ((retval = krb5_c_string_to_key(context, ks_tuple[i].ks_enctype,
4247c478bd9Sstevel@tonic-gate 					   &pwd, &key_salt.data, &key))) {
4257c478bd9Sstevel@tonic-gate 	     if (key_salt.data.data)
4267c478bd9Sstevel@tonic-gate 		  free(key_salt.data.data);
4277c478bd9Sstevel@tonic-gate 	     return(retval);
4287c478bd9Sstevel@tonic-gate 	}
4297c478bd9Sstevel@tonic-gate 
43056a424ccSmp 	if (key_salt.data.length == SALT_TYPE_AFS_LENGTH)
4317c478bd9Sstevel@tonic-gate 	    key_salt.data.length =
4327c478bd9Sstevel@tonic-gate 	      krb5_princ_realm(context, db_entry->princ)->length;
4337c478bd9Sstevel@tonic-gate 
43456a424ccSmp 	if ((retval = krb5_dbekd_encrypt_key_data(context, master_key, &key,
4357c478bd9Sstevel@tonic-gate 		     (const krb5_keysalt *)&key_salt,
43656a424ccSmp 		     kvno, &db_entry->key_data[db_entry->n_key_data-1]))) {
4377c478bd9Sstevel@tonic-gate 	    if (key_salt.data.data)
4387c478bd9Sstevel@tonic-gate 		 free(key_salt.data.data);
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	    krb5_free_keyblock_contents(context, &key);
4417c478bd9Sstevel@tonic-gate 	    return(retval);
4427c478bd9Sstevel@tonic-gate 	}
4437c478bd9Sstevel@tonic-gate 	if (key_salt.data.data)
4447c478bd9Sstevel@tonic-gate 	     free(key_salt.data.data);
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	krb5_free_keyblock_contents(context, &key);
4477c478bd9Sstevel@tonic-gate     }
4487c478bd9Sstevel@tonic-gate     return(retval);
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate /*
4527c478bd9Sstevel@tonic-gate  * Change password for a krb5_db_entry
4537c478bd9Sstevel@tonic-gate  * Assumes the max kvno
4547c478bd9Sstevel@tonic-gate  *
4557c478bd9Sstevel@tonic-gate  * As a side effect all old keys are nuked if keepold is false.
4567c478bd9Sstevel@tonic-gate  */
4577c478bd9Sstevel@tonic-gate krb5_error_code
458*54925bf6Swillf krb5_dbe_def_cpw(context, master_key, ks_tuple, ks_tuple_count, passwd,
4597c478bd9Sstevel@tonic-gate 	     new_kvno, keepold, db_entry)
4607c478bd9Sstevel@tonic-gate     krb5_context	  context;
4617c478bd9Sstevel@tonic-gate     krb5_keyblock       * master_key;
4627c478bd9Sstevel@tonic-gate     krb5_key_salt_tuple	* ks_tuple;
4637c478bd9Sstevel@tonic-gate     int			  ks_tuple_count;
4647c478bd9Sstevel@tonic-gate     char 		* passwd;
4657c478bd9Sstevel@tonic-gate     int			  new_kvno;
4667c478bd9Sstevel@tonic-gate     krb5_boolean	  keepold;
4677c478bd9Sstevel@tonic-gate     krb5_db_entry	* db_entry;
4687c478bd9Sstevel@tonic-gate {
4697c478bd9Sstevel@tonic-gate     int 		  key_data_count;
4707c478bd9Sstevel@tonic-gate     int			  n_new_key_data;
4717c478bd9Sstevel@tonic-gate     krb5_key_data 	* key_data;
4727c478bd9Sstevel@tonic-gate     krb5_error_code	  retval;
4737c478bd9Sstevel@tonic-gate     int			  old_kvno;
4747c478bd9Sstevel@tonic-gate     int			  i;
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate     /* First save the old keydata */
4777c478bd9Sstevel@tonic-gate     old_kvno = get_key_data_kvno(context, db_entry->n_key_data,
4787c478bd9Sstevel@tonic-gate 				 db_entry->key_data);
4797c478bd9Sstevel@tonic-gate     key_data_count = db_entry->n_key_data;
4807c478bd9Sstevel@tonic-gate     key_data = db_entry->key_data;
4817c478bd9Sstevel@tonic-gate     db_entry->key_data = NULL;
4827c478bd9Sstevel@tonic-gate     db_entry->n_key_data = 0;
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate     /* increment the kvno.  if the requested kvno is too small,
4857c478bd9Sstevel@tonic-gate        increment the old kvno */
4867c478bd9Sstevel@tonic-gate     if (new_kvno < old_kvno+1)
4877c478bd9Sstevel@tonic-gate        new_kvno = old_kvno+1;
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate     retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count,
4907c478bd9Sstevel@tonic-gate 			 passwd, db_entry, new_kvno);
4917c478bd9Sstevel@tonic-gate     if (retval) {
4927c478bd9Sstevel@tonic-gate 	cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
4937c478bd9Sstevel@tonic-gate 	db_entry->n_key_data = key_data_count;
4947c478bd9Sstevel@tonic-gate 	db_entry->key_data = key_data;
4957c478bd9Sstevel@tonic-gate     } else if (keepold) {
4967c478bd9Sstevel@tonic-gate 	n_new_key_data = db_entry->n_key_data;
4977c478bd9Sstevel@tonic-gate 	for (i = 0; i < key_data_count; i++) {
4987c478bd9Sstevel@tonic-gate 	    retval = krb5_dbe_create_key_data(context, db_entry);
4997c478bd9Sstevel@tonic-gate 	    if (retval) {
5007c478bd9Sstevel@tonic-gate 		cleanup_key_data(context, db_entry->n_key_data,
5017c478bd9Sstevel@tonic-gate 				 db_entry->key_data);
5027c478bd9Sstevel@tonic-gate 		break;
5037c478bd9Sstevel@tonic-gate 	    }
5047c478bd9Sstevel@tonic-gate 	    db_entry->key_data[i+n_new_key_data] = key_data[i];
5057c478bd9Sstevel@tonic-gate 	    memset(&key_data[i], 0, sizeof(krb5_key_data));
5067c478bd9Sstevel@tonic-gate 	}
507*54925bf6Swillf 	krb5_db_free( context, key_data );
5087c478bd9Sstevel@tonic-gate     } else {
5097c478bd9Sstevel@tonic-gate 	cleanup_key_data(context, key_data_count, key_data);
5107c478bd9Sstevel@tonic-gate     }
5117c478bd9Sstevel@tonic-gate     return(retval);
5127c478bd9Sstevel@tonic-gate }
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate /*
5157c478bd9Sstevel@tonic-gate  * Add password for a krb5_db_entry
5167c478bd9Sstevel@tonic-gate  * Assumes the max kvno
5177c478bd9Sstevel@tonic-gate  *
5187c478bd9Sstevel@tonic-gate  * As a side effect all old keys older than the max kvno are nuked.
5197c478bd9Sstevel@tonic-gate  */
5207c478bd9Sstevel@tonic-gate krb5_error_code
5217c478bd9Sstevel@tonic-gate krb5_dbe_apw(context, master_key, ks_tuple, ks_tuple_count, passwd, db_entry)
5227c478bd9Sstevel@tonic-gate     krb5_context	  context;
5237c478bd9Sstevel@tonic-gate     krb5_keyblock       * master_key;
5247c478bd9Sstevel@tonic-gate     krb5_key_salt_tuple	* ks_tuple;
5257c478bd9Sstevel@tonic-gate     int			  ks_tuple_count;
5267c478bd9Sstevel@tonic-gate     char 		* passwd;
5277c478bd9Sstevel@tonic-gate     krb5_db_entry	* db_entry;
5287c478bd9Sstevel@tonic-gate {
5297c478bd9Sstevel@tonic-gate     int 		  key_data_count;
5307c478bd9Sstevel@tonic-gate     krb5_key_data 	* key_data;
5317c478bd9Sstevel@tonic-gate     krb5_error_code	  retval;
5327c478bd9Sstevel@tonic-gate     int			  old_kvno, new_kvno;
5337c478bd9Sstevel@tonic-gate     int			  i;
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate     /* First save the old keydata */
5367c478bd9Sstevel@tonic-gate     old_kvno = get_key_data_kvno(context, db_entry->n_key_data,
5377c478bd9Sstevel@tonic-gate 				 db_entry->key_data);
5387c478bd9Sstevel@tonic-gate     key_data_count = db_entry->n_key_data;
5397c478bd9Sstevel@tonic-gate     key_data = db_entry->key_data;
5407c478bd9Sstevel@tonic-gate     db_entry->key_data = NULL;
5417c478bd9Sstevel@tonic-gate     db_entry->n_key_data = 0;
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate     /* increment the kvno */
5447c478bd9Sstevel@tonic-gate     new_kvno = old_kvno+1;
5457c478bd9Sstevel@tonic-gate 
54656a424ccSmp     if ((retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count,
54756a424ccSmp 			     passwd, db_entry, new_kvno))) {
5487c478bd9Sstevel@tonic-gate 	cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
5497c478bd9Sstevel@tonic-gate 	db_entry->n_key_data = key_data_count;
5507c478bd9Sstevel@tonic-gate 	db_entry->key_data = key_data;
5517c478bd9Sstevel@tonic-gate     } else {
5527c478bd9Sstevel@tonic-gate 	/* Copy keys with key_data_kvno == old_kvno */
5537c478bd9Sstevel@tonic-gate 	for (i = 0; i < key_data_count; i++) {
5547c478bd9Sstevel@tonic-gate 	    if (key_data[i].key_data_kvno == old_kvno) {
55556a424ccSmp 		if ((retval = krb5_dbe_create_key_data(context, db_entry))) {
5567c478bd9Sstevel@tonic-gate 		    cleanup_key_data(context, db_entry->n_key_data,
5577c478bd9Sstevel@tonic-gate 				     db_entry->key_data);
5587c478bd9Sstevel@tonic-gate 		    break;
5597c478bd9Sstevel@tonic-gate 		}
5607c478bd9Sstevel@tonic-gate 		/* We should decrypt/re-encrypt the data to use the same mkvno*/
5617c478bd9Sstevel@tonic-gate 		db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
5627c478bd9Sstevel@tonic-gate 		memset(&key_data[i], 0, sizeof(krb5_key_data));
5637c478bd9Sstevel@tonic-gate 	    }
5647c478bd9Sstevel@tonic-gate 	}
5657c478bd9Sstevel@tonic-gate 	cleanup_key_data(context, key_data_count, key_data);
5667c478bd9Sstevel@tonic-gate     }
5677c478bd9Sstevel@tonic-gate     return(retval);
5687c478bd9Sstevel@tonic-gate }
569