xref: /freebsd/crypto/krb5/src/lib/kdb/kdb_convert.c (revision b670c9bafc0e31c7609969bf374b2e80bdc00211)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
4  * Use is subject to license terms.
5  */
6 
7 /* #pragma ident        "@(#)kdb_convert.c      1.3     05/01/05 SMI" */
8 
9 /*
10  * This file contains api's for conversion of the kdb_incr_update_t
11  * struct(s) into krb5_db_entry struct(s) and vice-versa.
12  */
13 #include <k5-int.h>
14 #include <sys/types.h>
15 #include <com_err.h>
16 #include <locale.h>
17 #include <iprop_hdr.h>
18 #include "iprop.h"
19 #include <kdb.h>
20 #include <kdb_log.h>
21 
22 /* BEGIN CSTYLED */
23 #define ULOG_ENTRY_TYPE(upd, i) ((kdb_incr_update_t *)upd)->kdb_update.kdbe_t_val[i]
24 
25 #define ULOG_ENTRY(upd, i) ((kdb_incr_update_t *)upd)->kdb_update.kdbe_t_val[i].kdbe_val_t_u
26 
27 #define ULOG_ENTRY_KEYVAL(upd, i, j) ((kdb_incr_update_t *)upd)->kdb_update.kdbe_t_val[i].kdbe_val_t_u.av_keydata.av_keydata_val[j]
28 
29 #define ULOG_ENTRY_PRINC(upd, i, j) ((kdb_incr_update_t *)upd)->kdb_update.kdbe_t_val[i].kdbe_val_t_u.av_princ.k_components.k_components_val[j]
30 
31 #define ULOG_ENTRY_MOD_PRINC(upd, i, j) ((kdb_incr_update_t *)upd)->kdb_update.kdbe_t_val[i].kdbe_val_t_u.av_mod_princ.k_components.k_components_val[j]
32 /* END CSTYLED */
33 
34 typedef enum {
35     REG_PRINC = 0,
36     MOD_PRINC = 1
37 } princ_type;
38 
39 
40 /*
41  * This routine tracks the krb5_db_entry fields that have been modified
42  * (by comparing it to the db_entry currently present in principal.db)
43  * in the update.
44  */
45 static void
46 find_changed_attrs(krb5_db_entry *current, krb5_db_entry *new,
47                    krb5_boolean exclude_nra,
48                    kdbe_attr_type_t *attrs, int *nattrs)
49 {
50     int i = 0, j = 0;
51 
52     krb5_tl_data *first, *second;
53 
54     if (current->attributes != new->attributes)
55         attrs[i++] = AT_ATTRFLAGS;
56 
57     if (current->max_life != new->max_life)
58         attrs[i++] = AT_MAX_LIFE;
59 
60     if (current->max_renewable_life != new->max_renewable_life)
61         attrs[i++] = AT_MAX_RENEW_LIFE;
62 
63     if (current->expiration != new->expiration)
64         attrs[i++] = AT_EXP;
65 
66     if (current->pw_expiration != new->pw_expiration)
67         attrs[i++] = AT_PW_EXP;
68 
69     if (!exclude_nra) {
70         if (current->last_success != new->last_success)
71             attrs[i++] = AT_LAST_SUCCESS;
72 
73         if (current->last_failed != new->last_failed)
74             attrs[i++] = AT_LAST_FAILED;
75 
76         if (current->fail_auth_count != new->fail_auth_count)
77             attrs[i++] = AT_FAIL_AUTH_COUNT;
78     }
79 
80     if ((current->princ->type == new->princ->type) &&
81         (current->princ->length == new->princ->length)) {
82         if ((current->princ->realm.length ==
83              new->princ->realm.length) &&
84             strncmp(current->princ->realm.data,
85                     new->princ->realm.data,
86                     current->princ->realm.length)) {
87             for (j = 0; j < current->princ->length; j++) {
88                 if ((current->princ->data[j].data != NULL) &&
89                     (strncmp(current->princ->data[j].data,
90                              new->princ->data[j].data,
91                              current->princ->data[j].length))) {
92                     attrs[i++] = AT_PRINC;
93                     break;
94                 }
95             }
96         } else {
97             attrs[i++] = AT_PRINC;
98         }
99     } else {
100         attrs[i++] = AT_PRINC;
101     }
102 
103     if (current->n_key_data == new->n_key_data) {
104         /* Assuming key ordering is the same in new & current */
105         for (j = 0; j < new->n_key_data; j++) {
106             if (current->key_data[j].key_data_kvno !=
107                 new->key_data[j].key_data_kvno) {
108                 attrs[i++] = AT_KEYDATA;
109                 break;
110             }
111         }
112     } else {
113         attrs[i++] = AT_KEYDATA;
114     }
115 
116     if (current->n_tl_data == new->n_tl_data) {
117         /* Assuming we preserve the TL_DATA ordering between updates */
118         for (first = current->tl_data, second = new->tl_data;
119              first; first = first->tl_data_next,
120                  second = second->tl_data_next) {
121             if ((first->tl_data_length == second->tl_data_length) &&
122                 (first->tl_data_type == second->tl_data_type)) {
123                 if ((memcmp((char *)first->tl_data_contents,
124                             (char *)second->tl_data_contents,
125                             first->tl_data_length)) != 0) {
126                     attrs[i++] = AT_TL_DATA;
127                     break;
128                 }
129             } else {
130                 attrs[i++] = AT_TL_DATA;
131                 break;
132             }
133         }
134     } else {
135         attrs[i++] = AT_TL_DATA;
136     }
137 
138     if (current->len != new->len)
139         attrs[i++] = AT_LEN;
140     /*
141      * Store the no. of (possibly :)) changed attributes
142      */
143     *nattrs = i;
144 }
145 
146 
147 /* Initialize *u with a copy of d.  Return 0 on success, -1 on failure. */
148 static int
149 data_to_utf8str(utf8str_t *u, krb5_data d)
150 {
151     u->utf8str_t_len = d.length;
152     if (d.data) {
153         u->utf8str_t_val = malloc(d.length);
154         if (u->utf8str_t_val == NULL)
155             return -1;
156         memcpy(u->utf8str_t_val, d.data, d.length);
157     } else
158         u->utf8str_t_val = NULL;
159     return 0;
160 }
161 
162 /*
163  * Converts the krb5_principal struct from db2 to ulog format.
164  */
165 static krb5_error_code
166 conv_princ_2ulog(krb5_principal princ, kdb_incr_update_t *upd,
167                  int cnt, princ_type tp)
168 {
169     int i = 0;
170     kdbe_princ_t *p;
171     kdbe_data_t *components;
172 
173     if ((upd == NULL) || !princ)
174         return (KRB5KRB_ERR_GENERIC);
175 
176     switch (tp) {
177     case REG_PRINC:
178     case MOD_PRINC:
179         p = &ULOG_ENTRY(upd, cnt).av_princ; /* or av_mod_princ */
180         p->k_nametype = (int32_t)princ->type;
181 
182         if (data_to_utf8str(&p->k_realm, princ->realm) < 0) {
183             return ENOMEM;
184         }
185 
186         p->k_components.k_components_len = princ->length;
187 
188         p->k_components.k_components_val = components
189             = malloc(princ->length * sizeof (kdbe_data_t));
190         if (p->k_components.k_components_val == NULL) {
191             free(p->k_realm.utf8str_t_val);
192             p->k_realm.utf8str_t_val = NULL;
193             return (ENOMEM);
194         }
195 
196         memset(components, 0, princ->length * sizeof(kdbe_data_t));
197         for (i = 0; i < princ->length; i++)
198             components[i].k_data.utf8str_t_val = NULL;
199         for (i = 0; i < princ->length; i++) {
200             components[i].k_magic = princ->data[i].magic;
201             if (data_to_utf8str(&components[i].k_data, princ->data[i]) < 0) {
202                 int j;
203                 for (j = 0; j < i; j++) {
204                     free(components[j].k_data.utf8str_t_val);
205                     components[j].k_data.utf8str_t_val = NULL;
206                 }
207                 free(components);
208                 p->k_components.k_components_val = NULL;
209                 free(p->k_realm.utf8str_t_val);
210                 p->k_realm.utf8str_t_val = NULL;
211                 return ENOMEM;
212             }
213         }
214         break;
215 
216     default:
217         break;
218     }
219     return (0);
220 }
221 
222 /*
223  * Copies a UTF-8 string from ulog to a krb5_data object, which may
224  * already have allocated storage associated with it.
225  *
226  * Maybe a return value should indicate success/failure?
227  */
228 static void
229 set_from_utf8str(krb5_data *d, utf8str_t u)
230 {
231     if (u.utf8str_t_len > INT_MAX - 1) {
232         d->data = NULL;
233         return;
234     }
235     d->length = u.utf8str_t_len;
236     d->data = malloc(d->length + 1);
237     if (d->data == NULL)
238         return;
239     if (d->length)      /* Pointer may be null if length = 0.  */
240         strncpy(d->data, u.utf8str_t_val, d->length);
241     d->data[d->length] = 0;
242 }
243 
244 /*
245  * Converts the krb5_principal struct from ulog to db2 format.
246  */
247 static krb5_principal
248 conv_princ_2db(krb5_context context, kdbe_princ_t *kdbe_princ)
249 {
250     unsigned int i;
251     int j;
252     krb5_principal princ;
253     kdbe_data_t *components;
254 
255     princ = calloc(1, sizeof (krb5_principal_data));
256     if (princ == NULL) {
257         return NULL;
258     }
259     princ->length = 0;
260     princ->data = NULL;
261 
262     components = kdbe_princ->k_components.k_components_val;
263 
264     princ->type = (krb5_int32) kdbe_princ->k_nametype;
265     princ->realm.data = NULL;
266     set_from_utf8str(&princ->realm, kdbe_princ->k_realm);
267     if (princ->realm.data == NULL)
268         goto error;
269 
270     princ->data = calloc(kdbe_princ->k_components.k_components_len,
271                          sizeof (krb5_data));
272     if (princ->data == NULL)
273         goto error;
274     for (i = 0; i < kdbe_princ->k_components.k_components_len; i++)
275         princ->data[i].data = NULL;
276     princ->length = (krb5_int32)kdbe_princ->k_components.k_components_len;
277 
278     for (j = 0; j < princ->length; j++) {
279         princ->data[j].magic = components[j].k_magic;
280         set_from_utf8str(&princ->data[j], components[j].k_data);
281         if (princ->data[j].data == NULL)
282             goto error;
283     }
284 
285     return princ;
286 error:
287     krb5_free_principal(context, princ);
288     return NULL;
289 }
290 
291 
292 /*
293  * This routine converts a krb5 DB record into update log (ulog) entry format.
294  * Space for the update log entry should be allocated prior to invocation of
295  * this routine.
296  */
297 krb5_error_code
298 ulog_conv_2logentry(krb5_context context, krb5_db_entry *entry,
299                     kdb_incr_update_t *update)
300 {
301     int i, j, cnt, final, nattrs, tmpint;
302     krb5_principal tmpprinc;
303     krb5_tl_data *newtl;
304     krb5_db_entry *curr;
305     krb5_error_code ret;
306     kdbe_attr_type_t *attr_types;
307     int kadm_data_yes;
308 
309     nattrs = tmpint = 0;
310     final = -1;
311     kadm_data_yes = 0;
312     attr_types = NULL;
313 
314     /*
315      * XXX we rely on the good behaviour of the database not to
316      * exceed this limit.
317      */
318     if ((update->kdb_update.kdbe_t_val = (kdbe_val_t *)
319          malloc(MAXENTRY_SIZE)) == NULL) {
320         return (ENOMEM);
321     }
322 
323     /*
324      * Find out which attrs have been modified
325      */
326     if ((attr_types = (kdbe_attr_type_t *)malloc(
327              sizeof (kdbe_attr_type_t) * MAXATTRS_SIZE))
328         == NULL) {
329         return (ENOMEM);
330     }
331 
332     ret = krb5_db_get_principal(context, entry->princ, 0, &curr);
333     if (ret && ret != KRB5_KDB_NOENTRY) {
334         free(attr_types);
335         return (ret);
336     }
337 
338     if (ret == KRB5_KDB_NOENTRY) {
339         /*
340          * This is a new entry to the database, hence will
341          * include all the attribute-value pairs
342          *
343          * We leave out the TL_DATA types which we model as
344          * attrs in kdbe_attr_type_t, since listing AT_TL_DATA
345          * encompasses these other types-turned-attributes
346          *
347          * So, we do *NOT* consider AT_MOD_PRINC, AT_MOD_TIME,
348          * AT_MOD_WHERE, AT_PW_LAST_CHANGE, AT_PW_POLICY,
349          * AT_PW_POLICY_SWITCH, AT_PW_HIST_KVNO and AT_PW_HIST,
350          * totalling 8 attrs.
351          */
352         while (nattrs < MAXATTRS_SIZE - 8) {
353             attr_types[nattrs] = nattrs;
354             nattrs++;
355         }
356     } else {
357         /* Always exclude non-replicated attributes for now. */
358         find_changed_attrs(curr, entry, TRUE, attr_types, &nattrs);
359         krb5_db_free_principal(context, curr);
360     }
361 
362     for (i = 0; i < nattrs; i++) {
363         switch (attr_types[i]) {
364         case AT_ATTRFLAGS:
365             if (entry->attributes >= 0) {
366                 ULOG_ENTRY_TYPE(update, ++final).av_type =
367                     AT_ATTRFLAGS;
368                 ULOG_ENTRY(update, final).av_attrflags =
369                     (uint32_t)entry->attributes;
370             }
371             break;
372 
373         case AT_MAX_LIFE:
374             if (entry->max_life >= 0) {
375                 ULOG_ENTRY_TYPE(update, ++final).av_type = AT_MAX_LIFE;
376                 ULOG_ENTRY(update, final).av_max_life =
377                     (uint32_t)entry->max_life;
378             }
379             break;
380 
381         case AT_MAX_RENEW_LIFE:
382             if (entry->max_renewable_life >= 0) {
383                 ULOG_ENTRY_TYPE(update, ++final).av_type = AT_MAX_RENEW_LIFE;
384                 ULOG_ENTRY(update, final).av_max_renew_life =
385                     (uint32_t)entry->max_renewable_life;
386             }
387             break;
388 
389         case AT_EXP:
390             if (entry->expiration >= 0) {
391                 ULOG_ENTRY_TYPE(update, ++final).av_type = AT_EXP;
392                 ULOG_ENTRY(update, final).av_exp = (uint32_t)entry->expiration;
393             }
394             break;
395 
396         case AT_PW_EXP:
397             if (entry->pw_expiration >= 0) {
398                 ULOG_ENTRY_TYPE(update, ++final).av_type = AT_PW_EXP;
399                 ULOG_ENTRY(update, final).av_pw_exp =
400                     (uint32_t)entry->pw_expiration;
401             }
402             break;
403 
404         case AT_PRINC:
405             if (entry->princ->length > 0) {
406                 ULOG_ENTRY_TYPE(update, ++final).av_type = AT_PRINC;
407                 if ((ret = conv_princ_2ulog(entry->princ,
408                                             update, final, REG_PRINC))) {
409                     free(attr_types);
410                     return (ret);
411                 }
412             }
413             break;
414 
415         case AT_KEYDATA:
416 /* BEGIN CSTYLED */
417             if (entry->n_key_data >= 0) {
418                 ULOG_ENTRY_TYPE(update, ++final).av_type = AT_KEYDATA;
419                 ULOG_ENTRY(update, final).av_keydata.av_keydata_len =
420                     entry->n_key_data;
421                 ULOG_ENTRY(update, final).av_keydata.av_keydata_val =
422                     malloc(entry->n_key_data * sizeof (kdbe_key_t));
423                 if (ULOG_ENTRY(update, final).av_keydata.av_keydata_val ==
424                     NULL) {
425                     free(attr_types);
426                     return (ENOMEM);
427                 }
428 
429                 for (j = 0; j < entry->n_key_data; j++) {
430                     ULOG_ENTRY_KEYVAL(update, final, j).k_ver =
431                         entry->key_data[j].key_data_ver;
432                     ULOG_ENTRY_KEYVAL(update, final, j).k_kvno =
433                         entry->key_data[j].key_data_kvno;
434                     ULOG_ENTRY_KEYVAL(update, final, j).k_enctype.k_enctype_len = entry->key_data[j].key_data_ver;
435                     ULOG_ENTRY_KEYVAL(update, final, j).k_contents.k_contents_len = entry->key_data[j].key_data_ver;
436 
437                     ULOG_ENTRY_KEYVAL(update, final, j).k_enctype.k_enctype_val = malloc(entry->key_data[j].key_data_ver * sizeof(int32_t));
438                     if (ULOG_ENTRY_KEYVAL(update, final, j).k_enctype.k_enctype_val == NULL) {
439                         free(attr_types);
440                         return (ENOMEM);
441                     }
442 
443                     ULOG_ENTRY_KEYVAL(update, final, j).k_contents.k_contents_val = malloc(entry->key_data[j].key_data_ver * sizeof(utf8str_t));
444                     if (ULOG_ENTRY_KEYVAL(update, final, j).k_contents.k_contents_val == NULL) {
445                         free(attr_types);
446                         return (ENOMEM);
447                     }
448 
449                     for (cnt = 0; cnt < entry->key_data[j].key_data_ver;
450                          cnt++) {
451                         ULOG_ENTRY_KEYVAL(update, final, j).k_enctype.k_enctype_val[cnt] = entry->key_data[j].key_data_type[cnt];
452                         ULOG_ENTRY_KEYVAL(update, final, j).k_contents.k_contents_val[cnt].utf8str_t_len = entry->key_data[j].key_data_length[cnt];
453                         ULOG_ENTRY_KEYVAL(update, final, j).k_contents.k_contents_val[cnt].utf8str_t_val = malloc(entry->key_data[j].key_data_length[cnt] * sizeof (char));
454                         if (ULOG_ENTRY_KEYVAL(update, final, j).k_contents.k_contents_val[cnt].utf8str_t_val == NULL) {
455                             free(attr_types);
456                             return (ENOMEM);
457                         }
458                         (void) memcpy(ULOG_ENTRY_KEYVAL(update, final, j).k_contents.k_contents_val[cnt].utf8str_t_val, entry->key_data[j].key_data_contents[cnt], entry->key_data[j].key_data_length[cnt]);
459                     }
460                 }
461             }
462             break;
463 
464         case AT_TL_DATA:
465             ret = krb5_dbe_lookup_last_pwd_change(context, entry, &tmpint);
466             if (ret == 0) {
467                 ULOG_ENTRY_TYPE(update, ++final).av_type = AT_PW_LAST_CHANGE;
468                 ULOG_ENTRY(update, final).av_pw_last_change = tmpint;
469             }
470             tmpint = 0;
471 
472             if(!(ret = krb5_dbe_lookup_mod_princ_data(context, entry, &tmpint,
473                                                       &tmpprinc))) {
474 
475                 ULOG_ENTRY_TYPE(update, ++final).av_type = AT_MOD_PRINC;
476 
477                 ret = conv_princ_2ulog(tmpprinc, update, final, MOD_PRINC);
478                 krb5_free_principal(context, tmpprinc);
479                 if (ret) {
480                     free(attr_types);
481                     return (ret);
482                 }
483                 ULOG_ENTRY_TYPE(update, ++final).av_type = AT_MOD_TIME;
484                 ULOG_ENTRY(update, final).av_mod_time =
485                     tmpint;
486             }
487 
488             newtl = entry->tl_data;
489             while (newtl) {
490                 switch (newtl->tl_data_type) {
491                 case KRB5_TL_LAST_PWD_CHANGE:
492                 case KRB5_TL_MOD_PRINC:
493                     break;
494 
495                 case KRB5_TL_KADM_DATA:
496                 default:
497                     if (kadm_data_yes == 0) {
498                         ULOG_ENTRY_TYPE(update, ++final).av_type = AT_TL_DATA;
499                         ULOG_ENTRY(update, final).av_tldata.av_tldata_len = 0;
500                         ULOG_ENTRY(update, final).av_tldata.av_tldata_val =
501                             malloc(entry->n_tl_data * sizeof(kdbe_tl_t));
502 
503                         if (ULOG_ENTRY(update, final).av_tldata.av_tldata_val
504                             == NULL) {
505                             free(attr_types);
506                             return (ENOMEM);
507                         }
508                         kadm_data_yes = 1;
509                     }
510 
511                     tmpint = ULOG_ENTRY(update, final).av_tldata.av_tldata_len;
512                     ULOG_ENTRY(update, final).av_tldata.av_tldata_len++;
513                     ULOG_ENTRY(update, final).av_tldata.av_tldata_val[tmpint].tl_type = newtl->tl_data_type;
514                     ULOG_ENTRY(update, final).av_tldata.av_tldata_val[tmpint].tl_data.tl_data_len = newtl->tl_data_length;
515                     ULOG_ENTRY(update, final).av_tldata.av_tldata_val[tmpint].tl_data.tl_data_val = malloc(newtl->tl_data_length * sizeof (char));
516                     if (ULOG_ENTRY(update, final).av_tldata.av_tldata_val[tmpint].tl_data.tl_data_val == NULL) {
517                         free(attr_types);
518                         return (ENOMEM);
519                     }
520                     (void) memcpy(ULOG_ENTRY(update, final).av_tldata.av_tldata_val[tmpint].tl_data.tl_data_val, newtl->tl_data_contents, newtl->tl_data_length);
521                     break;
522                 }
523                 newtl = newtl->tl_data_next;
524             }
525             break;
526 /* END CSTYLED */
527 
528         case AT_LEN:
529             ULOG_ENTRY_TYPE(update, ++final).av_type = AT_LEN;
530             ULOG_ENTRY(update, final).av_len = (int16_t)entry->len;
531             break;
532 
533         default:
534             break;
535         }
536 
537     }
538 
539     free(attr_types);
540 
541     /*
542      * Update len field in kdb_update
543      */
544     update->kdb_update.kdbe_t_len = ++final;
545     return (0);
546 }
547 
548 /* Convert an update log (ulog) entry into a kerberos record. */
549 krb5_error_code
550 ulog_conv_2dbentry(krb5_context context, krb5_db_entry **entry,
551                    kdb_incr_update_t *update)
552 {
553     krb5_db_entry *ent = NULL;
554     int replica;
555     krb5_principal mod_princ = NULL;
556     int i, j, cnt = 0, mod_time = 0, nattrs;
557     krb5_principal dbprinc;
558     char *dbprincstr = NULL;
559     krb5_tl_data newtl;
560     krb5_error_code ret;
561     unsigned int prev_n_keys = 0;
562     krb5_boolean is_add;
563     void *newptr;
564 
565     *entry = NULL;
566 
567     replica = (context->kdblog_context != NULL) &&
568         (context->kdblog_context->iproprole == IPROP_REPLICA);
569 
570     /*
571      * Store the no. of changed attributes in nattrs
572      */
573     nattrs = update->kdb_update.kdbe_t_len;
574 
575     dbprincstr = k5memdup0(update->kdb_princ_name.utf8str_t_val,
576                            update->kdb_princ_name.utf8str_t_len, &ret);
577     if (dbprincstr == NULL)
578         goto cleanup;
579 
580     ret = krb5_parse_name(context, dbprincstr, &dbprinc);
581     free(dbprincstr);
582     if (ret)
583         goto cleanup;
584 
585     ret = krb5_db_get_principal(context, dbprinc, 0, &ent);
586     krb5_free_principal(context, dbprinc);
587     if (ret && ret != KRB5_KDB_NOENTRY)
588         goto cleanup;
589     is_add = (ret == KRB5_KDB_NOENTRY);
590 
591     /*
592      * Set ent->n_tl_data = 0 initially, if this is an ADD update
593      */
594     if (is_add) {
595         ent = calloc(1, sizeof(*ent));
596         if (ent == NULL)
597             return (ENOMEM);
598         ent->n_tl_data = 0;
599     }
600 
601     for (i = 0; i < nattrs; i++) {
602         krb5_principal tmpprinc = NULL;
603 
604 #define u (ULOG_ENTRY(update, i))
605         switch (ULOG_ENTRY_TYPE(update, i).av_type) {
606         case AT_ATTRFLAGS:
607             ent->attributes = (krb5_flags) u.av_attrflags;
608             break;
609 
610         case AT_MAX_LIFE:
611             ent->max_life = (krb5_deltat) u.av_max_life;
612             break;
613 
614         case AT_MAX_RENEW_LIFE:
615             ent->max_renewable_life = (krb5_deltat) u.av_max_renew_life;
616             break;
617 
618         case AT_EXP:
619             ent->expiration = (krb5_timestamp) u.av_exp;
620             break;
621 
622         case AT_PW_EXP:
623             ent->pw_expiration = (krb5_timestamp) u.av_pw_exp;
624             break;
625 
626         case AT_LAST_SUCCESS:
627             if (!replica)
628                 ent->last_success = (krb5_timestamp) u.av_last_success;
629             break;
630 
631         case AT_LAST_FAILED:
632             if (!replica)
633                 ent->last_failed = (krb5_timestamp) u.av_last_failed;
634             break;
635 
636         case AT_FAIL_AUTH_COUNT:
637             if (!replica)
638                 ent->fail_auth_count = (krb5_kvno) u.av_fail_auth_count;
639             break;
640 
641         case AT_PRINC:
642             tmpprinc = conv_princ_2db(context, &u.av_princ);
643             if (tmpprinc == NULL) {
644                 ret = ENOMEM;
645                 goto cleanup;
646             }
647             krb5_free_principal(context, ent->princ);
648             ent->princ = tmpprinc;
649             break;
650 
651         case AT_KEYDATA:
652             if (!is_add)
653                 prev_n_keys = ent->n_key_data;
654             else
655                 prev_n_keys = 0;
656             ent->n_key_data = (krb5_int16)u.av_keydata.av_keydata_len;
657             if (is_add)
658                 ent->key_data = NULL;
659 
660             /* Allocate one extra key data to avoid allocating zero bytes. */
661             newptr = realloc(ent->key_data, (ent->n_key_data + 1) *
662                              sizeof(krb5_key_data));
663             if (newptr == NULL) {
664                 ret = ENOMEM;
665                 goto cleanup;
666             }
667             ent->key_data = newptr;
668 
669 /* BEGIN CSTYLED */
670             for (j = prev_n_keys; j < ent->n_key_data; j++) {
671                 for (cnt = 0; cnt < 2; cnt++) {
672                     ent->key_data[j].key_data_contents[cnt] = NULL;
673                 }
674             }
675             for (j = 0; j < ent->n_key_data; j++) {
676                 krb5_key_data *kp = &ent->key_data[j];
677                 kdbe_key_t *kv = &ULOG_ENTRY_KEYVAL(update, i, j);
678                 kp->key_data_ver = (krb5_int16)kv->k_ver;
679                 kp->key_data_kvno = (krb5_ui_2)kv->k_kvno;
680                 if (kp->key_data_ver > 2) {
681                     ret = EINVAL; /* XXX ? */
682                     goto cleanup;
683                 }
684 
685                 for (cnt = 0; cnt < kp->key_data_ver; cnt++) {
686                     kp->key_data_type[cnt] =  (krb5_int16)kv->k_enctype.k_enctype_val[cnt];
687                     kp->key_data_length[cnt] = (krb5_int16)kv->k_contents.k_contents_val[cnt].utf8str_t_len;
688                     newptr = realloc(kp->key_data_contents[cnt],
689                                      kp->key_data_length[cnt]);
690                     if (newptr == NULL) {
691                         ret = ENOMEM;
692                         goto cleanup;
693                     }
694                     kp->key_data_contents[cnt] = newptr;
695 
696                     (void) memset(kp->key_data_contents[cnt], 0,
697                                   kp->key_data_length[cnt]);
698                     (void) memcpy(kp->key_data_contents[cnt],
699                                   kv->k_contents.k_contents_val[cnt].utf8str_t_val,
700                                   kp->key_data_length[cnt]);
701                 }
702             }
703             break;
704 
705         case AT_TL_DATA: {
706             for (j = 0; j < (int)u.av_tldata.av_tldata_len; j++) {
707                 newtl.tl_data_type = (krb5_int16)u.av_tldata.av_tldata_val[j].tl_type;
708                 newtl.tl_data_length = (krb5_int16)u.av_tldata.av_tldata_val[j].tl_data.tl_data_len;
709                 newtl.tl_data_contents = (krb5_octet *)u.av_tldata.av_tldata_val[j].tl_data.tl_data_val;
710                 newtl.tl_data_next = NULL;
711                 ret = krb5_dbe_update_tl_data(context, ent, &newtl);
712                 if (ret)
713                     goto cleanup;
714             }
715             break;
716 /* END CSTYLED */
717         }
718         case AT_PW_LAST_CHANGE:
719             ret = krb5_dbe_update_last_pwd_change(context, ent,
720                                                   u.av_pw_last_change);
721             if (ret)
722                 goto cleanup;
723             break;
724 
725         case AT_MOD_PRINC:
726             tmpprinc = conv_princ_2db(context, &u.av_mod_princ);
727             if (tmpprinc == NULL) {
728                 ret = ENOMEM;
729                 goto cleanup;
730             }
731             mod_princ = tmpprinc;
732             break;
733 
734         case AT_MOD_TIME:
735             mod_time = u.av_mod_time;
736             break;
737 
738         case AT_LEN:
739             ent->len = (krb5_int16) u.av_len;
740             break;
741 
742         default:
743             break;
744         }
745 #undef u
746     }
747 
748     /*
749      * process mod_princ_data request
750      */
751     if (mod_time && mod_princ) {
752         ret = krb5_dbe_update_mod_princ_data(context, ent,
753                                              mod_time, mod_princ);
754         if (ret)
755             goto cleanup;
756     }
757 
758     *entry = ent;
759     ent = NULL;
760     ret = 0;
761 cleanup:
762     krb5_db_free_principal(context, ent);
763     krb5_free_principal(context, mod_princ);
764     return ret;
765 }
766 
767 
768 
769 /*
770  * This routine frees up memory associated with the bunched ulog entries.
771  */
772 void
773 ulog_free_entries(kdb_incr_update_t *updates, int no_of_updates)
774 {
775 
776     kdb_incr_update_t *upd;
777     unsigned int i, j;
778     int k, cnt;
779 
780     if (updates == NULL)
781         return;
782 
783     upd = updates;
784 
785     /*
786      * Loop thru each ulog entry
787      */
788     for (cnt = 0; cnt < no_of_updates; cnt++) {
789 
790         /*
791          * ulog entry - kdb_princ_name
792          */
793         free(upd->kdb_princ_name.utf8str_t_val);
794 
795 /* BEGIN CSTYLED */
796 
797         /*
798          * ulog entry - kdb_kdcs_seen_by
799          */
800         if (upd->kdb_kdcs_seen_by.kdb_kdcs_seen_by_val) {
801             for (i = 0; i < upd->kdb_kdcs_seen_by.kdb_kdcs_seen_by_len; i++)
802                 free(upd->kdb_kdcs_seen_by.kdb_kdcs_seen_by_val[i].utf8str_t_val);
803             free(upd->kdb_kdcs_seen_by.kdb_kdcs_seen_by_val);
804         }
805 
806         /*
807          * ulog entry - kdb_futures
808          */
809         free(upd->kdb_futures.kdb_futures_val);
810 
811         /*
812          * ulog entry - kdb_update
813          */
814         if (upd->kdb_update.kdbe_t_val) {
815             /*
816              * Loop thru all the attributes and free up stuff
817              */
818             for (i = 0; i < upd->kdb_update.kdbe_t_len; i++) {
819 
820                 /*
821                  * Free av_key_data
822                  */
823                 if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_KEYDATA) && ULOG_ENTRY(upd, i).av_keydata.av_keydata_val) {
824 
825                     for (j = 0; j < ULOG_ENTRY(upd, i).av_keydata.av_keydata_len; j++) {
826                         free(ULOG_ENTRY_KEYVAL(upd, i, j).k_enctype.k_enctype_val);
827                         if (ULOG_ENTRY_KEYVAL(upd, i, j).k_contents.k_contents_val) {
828                             for (k = 0; k < ULOG_ENTRY_KEYVAL(upd, i, j).k_ver; k++) {
829                                 free(ULOG_ENTRY_KEYVAL(upd, i, j).k_contents.k_contents_val[k].utf8str_t_val);
830                             }
831                             free(ULOG_ENTRY_KEYVAL(upd, i, j).k_contents.k_contents_val);
832                         }
833                     }
834                     free(ULOG_ENTRY(upd, i).av_keydata.av_keydata_val);
835                 }
836 
837 
838                 /*
839                  * Free av_tl_data
840                  */
841                 if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_TL_DATA) && ULOG_ENTRY(upd, i).av_tldata.av_tldata_val) {
842                     for (j = 0; j < ULOG_ENTRY(upd, i).av_tldata.av_tldata_len; j++) {
843                         free(ULOG_ENTRY(upd, i).av_tldata.av_tldata_val[j].tl_data.tl_data_val);
844                     }
845                     free(ULOG_ENTRY(upd, i).av_tldata.av_tldata_val);
846                 }
847 
848                 /*
849                  * Free av_princ
850                  */
851                 if (ULOG_ENTRY_TYPE(upd, i).av_type == AT_PRINC) {
852                     free(ULOG_ENTRY(upd, i).av_princ.k_realm.utf8str_t_val);
853                     if (ULOG_ENTRY(upd, i).av_princ.k_components.k_components_val) {
854                         for (j = 0; j < ULOG_ENTRY(upd, i).av_princ.k_components.k_components_len; j++) {
855                             free(ULOG_ENTRY_PRINC(upd, i, j).k_data.utf8str_t_val);
856                         }
857                         free(ULOG_ENTRY(upd, i).av_princ.k_components.k_components_val);
858                     }
859                 }
860 
861                 /*
862                  * Free av_mod_princ
863                  */
864                 if (ULOG_ENTRY_TYPE(upd, i).av_type == AT_MOD_PRINC) {
865                     free(ULOG_ENTRY(upd, i).av_mod_princ.k_realm.utf8str_t_val);
866                     if (ULOG_ENTRY(upd, i).av_mod_princ.k_components.k_components_val) {
867                         for (j = 0; j < ULOG_ENTRY(upd, i).av_mod_princ.k_components.k_components_len; j++) {
868                             free(ULOG_ENTRY_MOD_PRINC(upd, i, j).k_data.utf8str_t_val);
869                         }
870                         free(ULOG_ENTRY(upd, i).av_mod_princ.k_components.k_components_val);
871                     }
872                 }
873 
874                 /*
875                  * Free av_mod_where
876                  */
877                 if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_MOD_WHERE) && ULOG_ENTRY(upd, i).av_mod_where.utf8str_t_val)
878                     free(ULOG_ENTRY(upd, i).av_mod_where.utf8str_t_val);
879 
880                 /*
881                  * Free av_pw_policy
882                  */
883                 if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_PW_POLICY) && ULOG_ENTRY(upd, i).av_pw_policy.utf8str_t_val)
884                     free(ULOG_ENTRY(upd, i).av_pw_policy.utf8str_t_val);
885 
886                 /*
887                  * XXX: Free av_pw_hist
888                  *
889                  * For now, we just free the pointer
890                  * to av_pw_hist_val, since we aren't
891                  * populating this union member in
892                  * the conv api function(s) anyways.
893                  */
894                 if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_PW_HIST) && ULOG_ENTRY(upd, i).av_pw_hist.av_pw_hist_val)
895                     free(ULOG_ENTRY(upd, i).av_pw_hist.av_pw_hist_val);
896 
897             }
898 
899             /*
900              * Free up the pointer to kdbe_t_val
901              */
902             free(upd->kdb_update.kdbe_t_val);
903         }
904 
905 /* END CSTYLED */
906 
907         /*
908          * Bump up to next struct
909          */
910         upd++;
911     }
912 
913 
914     /*
915      * Finally, free up the pointer to the bunched ulog entries
916      */
917     free(updates);
918 }
919