Imported Upstream version 1.10.2
[platform/upstream/krb5.git] / src / plugins / kdb / hdb / kdb_marshal.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* plugins/kdb/hdb/kdb_marshal.c */
3 /*
4  * Copyright 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 #include "k5-int.h"
28
29 #if HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32
33 #include <db.h>
34 #include <stdio.h>
35 #include <errno.h>
36 #include <utime.h>
37 #include "kdb5.h"
38 #include "kdb_hdb.h"
39
40 void
41 kh_free_Principal(krb5_context context,
42                   Principal *principal)
43 {
44     kh_db_context *kh = KH_DB_CONTEXT(context);
45
46     if (principal != NULL)
47         (*kh->heim_free_principal)(kh->hcontext, principal);
48 }
49
50 void
51 kh_free_Event(krb5_context context,
52               Event *event)
53 {
54     kh_free_Principal(context, event->principal);
55 }
56
57 void
58 kh_free_HostAddresses(krb5_context context,
59                       HostAddresses *addrs)
60 {
61     kh_db_context *kh = KH_DB_CONTEXT(context);
62
63     if (addrs != NULL)
64         (*kh->heim_free_addresses)(kh->hcontext, addrs);
65 }
66
67 #if 0
68 static krb5_error_code
69 kh_marshal_octet_string(krb5_context context,
70                         const krb5_data *in_data,
71                         heim_octet_string *out_data)
72 {
73     out_data->data = malloc(in_data->length);
74     if (out_data->data == NULL)
75         return ENOMEM;
76
77     memcpy(out_data->data, in_data->data, in_data->length);
78
79     out_data->length = in_data->length;
80
81     return 0;
82 }
83
84 static krb5_error_code
85 kh_unmarshal_octet_string_contents(krb5_context context,
86                                    const heim_octet_string *in_data,
87                                    krb5_data *out_data)
88 {
89     out_data->magic = KV5M_DATA;
90     out_data->data = malloc(in_data->length);
91     if (out_data->data == NULL)
92         return ENOMEM;
93
94     memcpy(out_data->data, in_data->data, in_data->length);
95
96     out_data->length = in_data->length;
97
98     return 0;
99 }
100
101 static krb5_error_code
102 kh_unmarshal_octet_string(krb5_context context,
103                           heim_octet_string *in_data,
104                           krb5_data **out_data)
105 {
106     krb5_error_code code;
107
108     *out_data = k5alloc(sizeof(krb5_data), &code);
109     if (code != 0)
110         return code;
111
112     code = kh_unmarshal_octet_string_contents(context, in_data, *out_data);
113     if (code != 0) {
114         free(*out_data);
115         *out_data = NULL;
116         return code;
117     }
118
119     return 0;
120 }
121 #endif
122
123 static krb5_error_code
124 kh_marshal_general_string(krb5_context context,
125                           const krb5_data *in_data,
126                           heim_general_string *out_str)
127 {
128     *out_str = malloc(in_data->length + 1);
129     if (*out_str == NULL)
130         return ENOMEM;
131
132     memcpy(*out_str, in_data->data, in_data->length);
133     (*out_str)[in_data->length] = '\0';
134
135     return 0;
136 }
137
138 static krb5_error_code
139 kh_unmarshal_general_string_contents(krb5_context context,
140                                      const heim_general_string in_str,
141                                      krb5_data *out_data)
142 {
143     out_data->magic = KV5M_DATA;
144     out_data->length = strlen(in_str);
145     out_data->data = malloc(out_data->length);
146     if (out_data->data == NULL)
147         return ENOMEM;
148
149     memcpy(out_data->data, in_str, out_data->length);
150     return 0;
151 }
152
153 #if 0
154 static krb5_error_code
155 kh_unmarshal_general_string(krb5_context context,
156                             const heim_general_string in_str,
157                             krb5_data **out_data)
158 {
159     krb5_error_code code;
160
161     *out_data = k5alloc(sizeof(krb5_data), &code);
162     if (code != 0)
163         return code;
164
165     code = kh_unmarshal_general_string_contents(context, in_str, *out_data);
166     if (code != 0) {
167         free(*out_data);
168         *out_data = NULL;
169         return code;
170     }
171
172     return 0;
173 }
174 #endif
175
176 krb5_error_code
177 kh_marshal_Principal(krb5_context context,
178                      krb5_const_principal kprinc,
179                      Principal **out_hprinc)
180 {
181     krb5_error_code code;
182     Principal *hprinc;
183     int i;
184
185     hprinc = k5alloc(sizeof(*hprinc), &code);
186     if (code != 0)
187         return code;
188
189     hprinc->name.name_type = kprinc->type;
190     hprinc->name.name_string.val = k5alloc(kprinc->length *
191                                            sizeof(heim_general_string),
192                                            &code);
193     if (code != 0) {
194         kh_free_Principal(context, hprinc);
195         return code;
196     }
197     for (i = 0; i < kprinc->length; i++) {
198         code = kh_marshal_general_string(context, &kprinc->data[i],
199                                          &hprinc->name.name_string.val[i]);
200         if (code != 0) {
201             kh_free_Principal(context, hprinc);
202             return code;
203         }
204         hprinc->name.name_string.len++;
205     }
206     code = kh_marshal_general_string(context, &kprinc->realm, &hprinc->realm);
207     if (code != 0) {
208         kh_free_Principal(context, hprinc);
209         return code;
210     }
211
212     *out_hprinc = hprinc;
213
214     return 0;
215 }
216
217 krb5_error_code
218 kh_unmarshal_Principal(krb5_context context,
219                        const Principal *hprinc,
220                        krb5_principal *out_kprinc)
221 {
222     krb5_error_code code;
223     krb5_principal kprinc;
224     unsigned int i;
225
226     kprinc = k5alloc(sizeof(*kprinc), &code);
227     if (code != 0)
228         return code;
229
230     kprinc->magic = KV5M_PRINCIPAL;
231     kprinc->type = hprinc->name.name_type;
232     kprinc->data = k5alloc(hprinc->name.name_string.len * sizeof(krb5_data),
233                            &code);
234     if (code != 0) {
235         krb5_free_principal(context, kprinc);
236         return code;
237     }
238     for (i = 0; i < hprinc->name.name_string.len; i++) {
239         code = kh_unmarshal_general_string_contents(context,
240                                                     hprinc->name.name_string.val[i],
241                                                     &kprinc->data[i]);
242         if (code != 0) {
243             krb5_free_principal(context, kprinc);
244             return code;
245         }
246         kprinc->length++;
247     }
248     code = kh_unmarshal_general_string_contents(context,
249                                                 hprinc->realm,
250                                                 &kprinc->realm);
251     if (code != 0) {
252         krb5_free_principal(context, kprinc);
253         return code;
254     }
255
256     *out_kprinc = kprinc;
257
258     return 0;
259 }
260
261 static krb5_error_code
262 kh_marshal_Event(krb5_context context,
263                  const krb5_db_entry *kentry,
264                  Event *event)
265 {
266     krb5_error_code code;
267     krb5_timestamp mod_time = 0;
268     krb5_principal mod_princ = NULL;
269
270     memset(event, 0, sizeof(*event));
271
272     code = krb5_dbe_lookup_mod_princ_data(context, (krb5_db_entry *)kentry,
273                                           &mod_time, &mod_princ);
274     if (code != 0)
275         return code;
276
277     event->time = mod_time;
278
279     if (mod_princ != NULL) {
280         code = kh_marshal_Principal(context, mod_princ, &event->principal);
281         if (code != 0) {
282             krb5_free_principal(context, mod_princ);
283             return code;
284         }
285     }
286
287     krb5_free_principal(context, mod_princ);
288
289     return 0;
290 }
291
292 static krb5_error_code
293 kh_unmarshal_Event(krb5_context context,
294                    const Event *event,
295                    krb5_db_entry *kentry)
296 {
297     krb5_error_code code;
298     krb5_principal princ = NULL;
299
300     if (event->principal != NULL) {
301         code = kh_unmarshal_Principal(context, event->principal, &princ);
302         if (code != 0)
303             return code;
304     }
305
306     code = krb5_dbe_update_mod_princ_data(context, kentry,
307                                           event->time, princ);
308
309     krb5_free_principal(context, princ);
310
311     return code;
312 }
313
314 static krb5_error_code
315 kh_marshal_HDBFlags(krb5_context context,
316                     krb5_flags kflags,
317                     HDBFlags *hflags)
318 {
319     memset(hflags, 0, sizeof(*hflags));
320
321     if (kflags & KRB5_KDB_DISALLOW_TGT_BASED)
322         hflags->initial = 1;
323     if ((kflags & KRB5_KDB_DISALLOW_FORWARDABLE) == 0)
324         hflags->forwardable = 1;
325     if ((kflags & KRB5_KDB_DISALLOW_PROXIABLE) == 0)
326         hflags->proxiable = 1;
327     if ((kflags & KRB5_KDB_DISALLOW_RENEWABLE) == 0)
328         hflags->renewable = 1;
329     if ((kflags & KRB5_KDB_DISALLOW_POSTDATED) == 0)
330         hflags->postdate = 1;
331     if ((kflags & KRB5_KDB_DISALLOW_SVR) == 0)
332         hflags->server = 1;
333     hflags->client = 1;
334     if (kflags & KRB5_KDB_DISALLOW_ALL_TIX)
335         hflags->invalid = 1;
336     if (kflags & KRB5_KDB_REQUIRES_PRE_AUTH)
337         hflags->require_preauth = 1;
338     if (kflags & KRB5_KDB_PWCHANGE_SERVICE)
339         hflags->change_pw = 1;
340     if (kflags & KRB5_KDB_REQUIRES_HW_AUTH)
341         hflags->require_hwauth = 1;
342     if (kflags & KRB5_KDB_OK_AS_DELEGATE)
343         hflags->ok_as_delegate = 1;
344     /* hflags->user_to_user */
345     /* hflags->immutable */
346     if (kflags & KRB5_KDB_OK_TO_AUTH_AS_DELEGATE)
347         hflags->trusted_for_delegation = 1;
348     /* hflags->allow_kerberos4 */
349     /* hflags->allow_digest */
350
351     return 0;
352 }
353
354 static krb5_error_code
355 kh_unmarshal_HDBFlags(krb5_context context,
356                       HDBFlags hflags,
357                       krb5_flags *kflags)
358 {
359     *kflags = 0;
360
361     if (hflags.initial)
362         *kflags |= KRB5_KDB_DISALLOW_TGT_BASED;
363     if (!hflags.forwardable)
364         *kflags |= KRB5_KDB_DISALLOW_FORWARDABLE;
365     if (!hflags.proxiable)
366         *kflags |= KRB5_KDB_DISALLOW_PROXIABLE;
367     if (!hflags.renewable)
368         *kflags |= KRB5_KDB_DISALLOW_RENEWABLE;
369     if (!hflags.postdate)
370         *kflags |= KRB5_KDB_DISALLOW_POSTDATED;
371     if (!hflags.server)
372         *kflags |= KRB5_KDB_DISALLOW_SVR;
373     if (hflags.client)
374         ;
375     if (hflags.invalid)
376         *kflags |= KRB5_KDB_DISALLOW_ALL_TIX;
377     if (hflags.require_preauth)
378         *kflags |= KRB5_KDB_REQUIRES_PRE_AUTH;
379     if (hflags.change_pw)
380         *kflags |= KRB5_KDB_PWCHANGE_SERVICE;
381     if (hflags.require_hwauth)
382         *kflags |= KRB5_KDB_REQUIRES_HW_AUTH;
383     if (hflags.ok_as_delegate)
384         *kflags |= KRB5_KDB_OK_AS_DELEGATE;
385     if (hflags.user_to_user)
386         ;
387     if (hflags.immutable)
388         ;
389     if (hflags.trusted_for_delegation)
390         *kflags |= KRB5_KDB_OK_TO_AUTH_AS_DELEGATE;
391     if (hflags.allow_kerberos4)
392         ;
393     if (hflags.allow_digest)
394         ;
395     return 0;
396 }
397
398 static krb5_error_code
399 kh_marshal_Key(krb5_context context,
400                const krb5_key_data *kkey,
401                Key *hkey)
402 {
403     krb5_error_code code;
404
405     memset(hkey, 0, sizeof(*hkey));
406
407     hkey->key.keytype = kkey->key_data_type[0];
408     hkey->key.keyvalue.data = k5alloc(kkey->key_data_length[0], &code);
409     if (code != 0)
410         return code;
411     memcpy(hkey->key.keyvalue.data, kkey->key_data_contents[0],
412            kkey->key_data_length[0]);
413     hkey->key.keyvalue.length = kkey->key_data_length[0];
414
415     if (kkey->key_data_contents[1] != NULL) {
416         Salt *salt;
417
418         salt = k5alloc(sizeof(*salt), &code);
419         if (code != 0)
420             goto cleanup;
421
422         switch (kkey->key_data_type[1]) {
423         case KRB5_KDB_SALTTYPE_NORMAL:
424             salt->type = hdb_pw_salt;
425             break;
426         case KRB5_KDB_SALTTYPE_AFS3:
427             salt->type = hdb_afs3_salt;
428             break;
429         default:
430             salt->type = 0;
431             break;
432         }
433
434         salt->salt.data = k5alloc(kkey->key_data_length[1], &code);
435         if (code != 0) {
436             free(salt);
437             goto cleanup;
438         }
439         memcpy(salt->salt.data, kkey->key_data_contents[1],
440                kkey->key_data_length[1]);
441         salt->salt.length = kkey->key_data_length[1];
442
443         hkey->salt = salt;
444     }
445
446 cleanup:
447     if (code != 0 && hkey->key.keyvalue.data != NULL)
448         free(hkey->key.keyvalue.data);
449
450     return code;
451 }
452
453 static krb5_error_code
454 kh_unmarshal_Key(krb5_context context,
455                  const hdb_entry *hentry,
456                  const Key *hkey,
457                  krb5_key_data *kkey)
458 {
459     memset(kkey, 0, sizeof(*kkey));
460
461     kkey->key_data_ver = KRB5_KDB_V1_KEY_DATA_ARRAY;
462     kkey->key_data_kvno = hentry->kvno;
463
464     kkey->key_data_type[0] = hkey->key.keytype;
465     kkey->key_data_contents[0] = malloc(hkey->key.keyvalue.length);
466     if (kkey->key_data_contents[0] == NULL)
467         return ENOMEM;
468
469     memcpy(kkey->key_data_contents[0], hkey->key.keyvalue.data,
470            hkey->key.keyvalue.length);
471     kkey->key_data_length[0] = hkey->key.keyvalue.length;
472
473     if (hkey->salt != NULL) {
474         switch (hkey->salt->type) {
475         case hdb_pw_salt:
476             kkey->key_data_type[1] = KRB5_KDB_SALTTYPE_NORMAL;
477             break;
478         case hdb_afs3_salt:
479             kkey->key_data_type[1] = KRB5_KDB_SALTTYPE_AFS3;
480             break;
481         default:
482             kkey->key_data_type[1] = KRB5_KDB_SALTTYPE_SPECIAL;
483             break;
484         }
485
486         kkey->key_data_contents[1] = malloc(hkey->salt->salt.length);
487         if (kkey->key_data_contents[1] == NULL) {
488             memset(kkey->key_data_contents[0], 0, kkey->key_data_length[0]);
489             free(kkey->key_data_contents[0]);
490             return ENOMEM;
491         }
492         memcpy(kkey->key_data_contents[1], hkey->salt->salt.data,
493                hkey->salt->salt.length);
494         kkey->key_data_length[1] = hkey->salt->salt.length;
495     }
496
497     return 0;
498 }
499
500 /*
501  * Extension marshalers
502  */
503
504 static krb5_error_code
505 kh_marshal_HDB_extension_data_last_pw_change(krb5_context context,
506                                              const krb5_db_entry *kentry,
507                                              HDB_extension *hext)
508 {
509     krb5_timestamp stamp;
510     krb5_error_code code;
511
512     code = krb5_dbe_lookup_last_pwd_change(context,
513                                            (krb5_db_entry *)kentry, &stamp);
514     if (code != 0)
515         return code;
516
517     hext->data.u.last_pw_change = stamp;
518
519     return 0;
520 }
521
522 static krb5_error_code
523 kh_unmarshal_HDB_extension_data_last_pw_change(krb5_context context,
524                                                HDB_extension *hext,
525                                                krb5_db_entry *kentry)
526 {
527     return krb5_dbe_update_last_pwd_change(context, kentry,
528                                            hext->data.u.last_pw_change);
529 }
530
531 typedef krb5_error_code (*kh_hdb_marshal_extension_fn)(krb5_context,
532                                                        const krb5_db_entry *,
533                                                        HDB_extension *);
534
535 typedef krb5_error_code (*kh_hdb_unmarshal_extension_fn)(krb5_context,
536                                                          HDB_extension *,
537                                                          krb5_db_entry *);
538
539 struct {
540     kh_hdb_marshal_extension_fn marshal;
541     kh_hdb_unmarshal_extension_fn unmarshal;
542 } kh_hdb_extension_vtable[] = {
543     { NULL, NULL }, /* choice_HDB_extension_data_asn1_ellipsis */
544     { NULL, NULL }, /* choice_HDB_extension_data_pkinit_acl */
545     { NULL, NULL }, /* choice_HDB_extension_data_pkinit_cert_hash */
546     { NULL, NULL }, /* choice_HDB_extension_data_allowed_to_delegate_to */
547     { NULL, NULL }, /* choice_HDB_extension_data_lm_owf */
548     { NULL, NULL }, /* choice_HDB_extension_data_password */
549     { NULL, NULL }, /* choice_HDB_extension_data_aliases */
550     { kh_marshal_HDB_extension_data_last_pw_change,
551       kh_unmarshal_HDB_extension_data_last_pw_change }
552 };
553
554 static const size_t kh_hdb_extension_count =
555     sizeof(kh_hdb_extension_vtable) / sizeof(kh_hdb_extension_vtable[0]);
556
557 static krb5_error_code
558 kh_marshal_HDB_extension(krb5_context context,
559                          const krb5_db_entry *kentry,
560                          HDB_extension *hext)
561 {
562     kh_hdb_marshal_extension_fn marshal = NULL;
563
564     if (hext->data.element < kh_hdb_extension_count)
565         marshal = kh_hdb_extension_vtable[hext->data.element].marshal;
566
567     if (marshal == NULL)
568         return KRB5_KDB_DBTYPE_NOSUP;
569
570     return (*marshal)(context, kentry, hext);
571 }
572
573 static krb5_error_code
574 kh_unmarshal_HDB_extension(krb5_context context,
575                            HDB_extension *hext,
576                            krb5_db_entry *kentry)
577 {
578     kh_hdb_unmarshal_extension_fn unmarshal = NULL;
579
580     if (hext->data.element < kh_hdb_extension_count)
581         unmarshal = kh_hdb_extension_vtable[hext->data.element].unmarshal;
582
583     if (unmarshal == NULL)
584         return hext->mandatory ? KRB5_KDB_DBTYPE_NOSUP : 0;
585
586     return (*unmarshal)(context, hext, kentry);
587 }
588
589 static krb5_error_code
590 kh_marshal_HDB_extensions(krb5_context context,
591                           const krb5_db_entry *kentry,
592                           HDB_extensions *hexts)
593 {
594     unsigned int i;
595     krb5_error_code code;
596
597     hexts->val = k5alloc(kh_hdb_extension_count * sizeof(HDB_extension), &code);
598     if (code != 0)
599         return code;
600
601     hexts->len = 0;
602
603     for (i = 0; i < kh_hdb_extension_count; i++) {
604         HDB_extension *hext = &hexts->val[hexts->len];
605
606         hext->data.element = i;
607
608         code = kh_marshal_HDB_extension(context, kentry, hext);
609         if (code == KRB5_KDB_DBTYPE_NOSUP)
610             continue;
611         else if (code != 0)
612             break;
613
614         hexts->len++;
615     }
616
617     return code;
618 }
619
620 static krb5_error_code
621 kh_unmarshal_HDB_extensions(krb5_context context,
622                             HDB_extensions *hexts,
623                             krb5_db_entry *kentry)
624 {
625     unsigned int i;
626     krb5_error_code code = 0;
627
628     for (i = 0; i < hexts->len; i++) {
629         code = kh_unmarshal_HDB_extension(context, &hexts->val[i], kentry);
630         if (code != 0)
631             break;
632     }
633
634     return code;
635 }
636
637 krb5_error_code
638 kh_marshal_hdb_entry(krb5_context context,
639                      const krb5_db_entry *kentry,
640                      hdb_entry *hentry)
641 {
642     kh_db_context *kh = KH_DB_CONTEXT(context);
643     krb5_error_code code;
644     krb5_int16 kvno = 0;
645     int i;
646
647     memset(hentry, 0, sizeof(*hentry));
648
649     code = kh_marshal_Principal(context, kentry->princ, &hentry->principal);
650     if (code != 0)
651         goto cleanup;
652
653     code = kh_marshal_HDBFlags(context, kentry->attributes, &hentry->flags);
654     if (code != 0)
655         goto cleanup;
656
657     if (kentry->expiration) {
658         hentry->valid_end = k5alloc(sizeof(KerberosTime), &code);
659         if (code != 0)
660             goto cleanup;
661         *(hentry->valid_end) = kentry->expiration;
662     }
663     if (kentry->pw_expiration) {
664         hentry->pw_end = k5alloc(sizeof(KerberosTime), &code);
665         if (code != 0)
666             goto cleanup;
667         *(hentry->pw_end) = kentry->pw_expiration;
668     }
669     if (kentry->max_life) {
670         hentry->max_life = k5alloc(sizeof(unsigned int), &code);
671         if (code != 0)
672             goto cleanup;
673         *(hentry->max_life) = kentry->max_life;
674     }
675     if (kentry->max_renewable_life) {
676         hentry->max_renew = k5alloc(sizeof(unsigned int), &code);
677         if (code != 0)
678             goto cleanup;
679         *(hentry->max_renew) = kentry->max_renewable_life;
680     }
681
682     /* last_success */
683     /* last_failed */
684     /* fail_auth_count */
685     /* n_tl_data */
686
687     if ((kentry->attributes & KRB5_KDB_NEW_PRINC) == 0) {
688         hentry->modified_by = k5alloc(sizeof(Event), &code);
689         if (code != 0)
690             goto cleanup;
691         code = kh_marshal_Event(context, kentry, hentry->modified_by);
692     } else {
693         code = kh_marshal_Event(context, kentry, &hentry->created_by);
694     }
695     if (code != 0)
696         goto cleanup;
697
698     hentry->extensions = k5alloc(sizeof(HDB_extensions), &code);
699     if (code != 0)
700         goto cleanup;
701
702     code = kh_marshal_HDB_extensions(context, kentry, hentry->extensions);
703     if (code != 0)
704         goto cleanup;
705
706     hentry->keys.len = 0;
707     hentry->keys.val = k5alloc(kentry->n_key_data * sizeof(Key), &code);
708     if (code != 0)
709         goto cleanup;
710
711     for (i = 0; i < kentry->n_key_data; i++) {
712         code = kh_marshal_Key(context,
713                               &kentry->key_data[i],
714                               &hentry->keys.val[hentry->keys.len]);
715         if (code != 0)
716             goto cleanup;
717
718         if (kentry->key_data[i].key_data_kvno > kvno)
719             kvno = kentry->key_data[i].key_data_kvno;
720
721         hentry->keys.len++;
722     }
723
724     hentry->kvno = kvno;
725
726 cleanup:
727     if (code != 0) {
728         hdb_entry_ex hext;
729
730         hext.ctx = NULL;
731         hext.entry = *hentry;
732         hext.free_entry = NULL;
733
734         kh_hdb_free_entry(context, kh, &hext);
735         memset(hentry, 0, sizeof(*hentry));
736     }
737
738     return code;
739 }
740
741 krb5_error_code
742 kh_unmarshal_hdb_entry(krb5_context context,
743                        const hdb_entry *hentry,
744                        krb5_db_entry **kentry_ptr)
745 {
746     kh_db_context *kh = KH_DB_CONTEXT(context);
747     krb5_db_entry *kentry;
748     krb5_error_code code;
749     unsigned int i;
750
751     kentry = k5alloc(sizeof(*kentry), &code);
752     if (kentry == NULL)
753         return code;
754
755     kentry->magic = KRB5_KDB_MAGIC_NUMBER;
756     kentry->len = KRB5_KDB_V1_BASE_LENGTH;
757
758     code = kh_unmarshal_Principal(context, hentry->principal, &kentry->princ);
759     if (code != 0)
760         goto cleanup;
761
762     code = kh_unmarshal_HDBFlags(context, hentry->flags, &kentry->attributes);
763     if (code != 0)
764         goto cleanup;
765
766     if (hentry->max_life != NULL)
767         kentry->max_life = *(hentry->max_life);
768     if (hentry->max_renew != NULL)
769         kentry->max_renewable_life = *(hentry->max_renew);
770     if (hentry->valid_end != NULL)
771         kentry->expiration = *(hentry->valid_end);
772     if (hentry->pw_end != NULL)
773         kentry->pw_expiration = *(hentry->pw_end);
774
775     /* last_success */
776     /* last_failed */
777     /* fail_auth_count */
778     /* n_tl_data */
779
780     code = kh_unmarshal_Event(context,
781                               hentry->modified_by ? hentry->modified_by :
782                               &hentry->created_by,
783                               kentry);
784     if (code != 0)
785         goto cleanup;
786
787     code = kh_unmarshal_HDB_extensions(context, hentry->extensions, kentry);
788     if (code != 0)
789         goto cleanup;
790
791     kentry->key_data = k5alloc(hentry->keys.len * sizeof(krb5_key_data), &code);
792     if (code != 0)
793         goto cleanup;
794
795     for (i = 0; i < hentry->keys.len; i++) {
796         code = kh_unmarshal_Key(context, hentry,
797                                 &hentry->keys.val[i],
798                                 &kentry->key_data[i]);
799         if (code != 0)
800             goto cleanup;
801
802         kentry->n_key_data++;
803     }
804
805     *kentry_ptr = kentry;
806     kentry = NULL;
807
808 cleanup:
809     kh_kdb_free_entry(context, kh, kentry);
810     return code;
811 }