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