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