Account lockout
[krb5.git] / src / lib / kdb / kdb_convert.c
1 /*
2  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5
6 /* #pragma ident        "@(#)kdb_convert.c      1.3     05/01/05 SMI" */
7
8 /*
9  * This file contains api's for conversion of the kdb_incr_update_t
10  * struct(s) into krb5_db_entry struct(s) and vice-versa.
11  */
12 #include <sys/types.h>
13 #include <com_err.h>
14 #include <locale.h>
15 #include <errno.h>
16 #include <iprop_hdr.h>
17 #include "iprop.h"
18 #include <k5-int.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 /*
148  */
149 static int
150 data_to_utf8str(utf8str_t *u, krb5_data d)
151 {
152     u->utf8str_t_len = d.length;
153     if (d.data) {
154         u->utf8str_t_val = malloc(d.length);
155         if (u->utf8str_t_val == NULL)
156             return -1;
157         memcpy(u->utf8str_t_val, d.data, d.length);
158     } else
159         u->utf8str_t_val = NULL;
160     return 0;
161 }
162
163 /*
164  * Converts the krb5_principal struct from db2 to ulog format.
165  */
166 static krb5_error_code
167 conv_princ_2ulog(krb5_principal princ, kdb_incr_update_t *upd,
168                  int cnt, princ_type tp)
169 {
170     int i = 0;
171     kdbe_princ_t *p;
172     kdbe_data_t *components;
173
174     if ((upd == NULL) || !princ)
175         return (KRB5KRB_ERR_GENERIC);
176
177     switch (tp) {
178     case REG_PRINC:
179     case MOD_PRINC:
180         p = &ULOG_ENTRY(upd, cnt).av_princ; /* or av_mod_princ */
181         p->k_nametype = (int32_t)princ->type;
182
183         if (data_to_utf8str(&p->k_realm, princ->realm) < 0) {
184             return ENOMEM;
185         }
186
187         p->k_components.k_components_len = princ->length;
188
189         p->k_components.k_components_val = components
190             = malloc(princ->length * sizeof (kdbe_data_t));
191         if (p->k_components.k_components_val == NULL) {
192             free(p->k_realm.utf8str_t_val);
193             p->k_realm.utf8str_t_val = NULL;
194             return (ENOMEM);
195         }
196
197         memset(components, 0, princ->length * sizeof(kdbe_data_t));
198         for (i = 0; i < princ->length; i++)
199             components[i].k_data.utf8str_t_val = NULL;
200         for (i = 0; i < princ->length; i++) {
201             components[i].k_magic = princ->data[i].magic;
202             if (data_to_utf8str(&components[i].k_data, princ->data[i]) < 0) {
203                 int j;
204                 for (j = 0; j < i; j++) {
205                     free(components[j].k_data.utf8str_t_val);
206                     components[j].k_data.utf8str_t_val = NULL;
207                 }
208                 free(components);
209                 p->k_components.k_components_val = NULL;
210                 free(p->k_realm.utf8str_t_val);
211                 p->k_realm.utf8str_t_val = NULL;
212                 return ENOMEM;
213             }
214         }
215         break;
216
217     default:
218         break;
219     }
220     return (0);
221 }
222
223 /*
224  * Copies a UTF-8 string from ulog to a krb5_data object, which may
225  * already have allocated storage associated with it.
226  *
227  * Maybe a return value should indicate success/failure?
228  */
229 static void
230 set_from_utf8str(krb5_data *d, utf8str_t u)
231 {
232     if (u.utf8str_t_len > INT_MAX-1 || u.utf8str_t_len >= SIZE_MAX-1) {
233         d->data = NULL;
234         return;
235     }
236     d->length = u.utf8str_t_len;
237     d->data = malloc(d->length + 1);
238     if (d->data == NULL)
239         return;
240     if (d->length)      /* Pointer may be null if length = 0.  */
241         strncpy(d->data, u.utf8str_t_val, d->length);
242     d->data[d->length] = 0;
243 }
244
245 /*
246  * Converts the krb5_principal struct from ulog to db2 format.
247  */
248 static krb5_principal
249 conv_princ_2db(krb5_context context, kdbe_princ_t *kdbe_princ)
250 {
251     int i;
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 (i = 0; i < princ->length; i++) {
279         princ->data[i].magic = components[i].k_magic;
280         set_from_utf8str(&princ->data[i], components[i].k_data);
281         if (princ->data[i].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 one or more krb5 db2 records into update
294  * log (ulog) entry format. Space for the update log entries should
295  * be allocated prior to invocation of this routine.
296  */
297 krb5_error_code
298 ulog_conv_2logentry(krb5_context context, krb5_db_entry *entries,
299                     kdb_incr_update_t *updates,
300                     int nentries)
301 {
302     int i, j, k, cnt, final, nattrs, tmpint, nprincs;
303     unsigned int more;
304     krb5_principal tmpprinc;
305     krb5_tl_data *newtl;
306     krb5_db_entry curr;
307     krb5_error_code ret;
308     kdbe_attr_type_t *attr_types;
309     kdb_incr_update_t *upd;
310     krb5_db_entry *ent;
311     int kadm_data_yes;
312     /* always exclude non-replicated attributes, for now */
313     krb5_boolean exclude_nra = TRUE;
314
315     if ((updates == NULL) || (entries == NULL))
316         return (KRB5KRB_ERR_GENERIC);
317
318     upd = updates;
319     ent = entries;
320
321     for (k = 0; k < nentries; k++) {
322         nprincs = nattrs = tmpint = 0;
323         final = -1;
324         kadm_data_yes = 0;
325         attr_types = NULL;
326
327         /*
328          * XXX we rely on the good behaviour of the database not to
329          * exceed this limit.
330          */
331         if ((upd->kdb_update.kdbe_t_val = (kdbe_val_t *)
332              malloc(MAXENTRY_SIZE)) == NULL) {
333             return (ENOMEM);
334         }
335
336         /*
337          * Find out which attrs have been modified
338          */
339         if ((attr_types = (kdbe_attr_type_t *)malloc(
340                  sizeof (kdbe_attr_type_t) * MAXATTRS_SIZE))
341             == NULL) {
342             return (ENOMEM);
343         }
344
345         if ((ret = krb5_db_get_principal(context, ent->princ, &curr,
346                                          &nprincs, &more))) {
347             free(attr_types);
348             return (ret);
349         }
350
351         if (nprincs == 0) {
352             /*
353              * This is a new entry to the database, hence will
354              * include all the attribute-value pairs
355              *
356              * We leave out the TL_DATA types which we model as
357              * attrs in kdbe_attr_type_t, since listing AT_TL_DATA
358              * encompasses these other types-turned-attributes
359              *
360              * So, we do *NOT* consider AT_MOD_PRINC, AT_MOD_TIME,
361              * AT_MOD_WHERE, AT_PW_LAST_CHANGE, AT_PW_POLICY,
362              * AT_PW_POLICY_SWITCH, AT_PW_HIST_KVNO and AT_PW_HIST,
363              * totalling 8 attrs.
364              */
365             while (nattrs < MAXATTRS_SIZE - 8) {
366                 attr_types[nattrs] = nattrs;
367                 nattrs++;
368             }
369         } else {
370             find_changed_attrs(&curr, ent, exclude_nra, attr_types, &nattrs);
371
372             krb5_db_free_principal(context, &curr, nprincs);
373         }
374
375         for (i = 0; i < nattrs; i++) {
376             switch (attr_types[i]) {
377             case AT_ATTRFLAGS:
378                 if (ent->attributes >= 0) {
379                     ULOG_ENTRY_TYPE(upd, ++final).av_type =
380                         AT_ATTRFLAGS;
381                     ULOG_ENTRY(upd, final).av_attrflags =
382                         (uint32_t)ent->attributes;
383                 }
384                 break;
385
386             case AT_MAX_LIFE:
387                 if (ent->max_life >= 0) {
388                     ULOG_ENTRY_TYPE(upd, ++final).av_type =
389                         AT_MAX_LIFE;
390                     ULOG_ENTRY(upd, final).av_max_life =
391                         (uint32_t)ent->max_life;
392                 }
393                 break;
394
395             case AT_MAX_RENEW_LIFE:
396                 if (ent->max_renewable_life >= 0) {
397                     ULOG_ENTRY_TYPE(upd, ++final).av_type =
398                         AT_MAX_RENEW_LIFE;
399                     ULOG_ENTRY(upd,
400                                final).av_max_renew_life =
401                         (uint32_t)ent->max_renewable_life;
402                 }
403                 break;
404
405             case AT_EXP:
406                 if (ent->expiration >= 0) {
407                     ULOG_ENTRY_TYPE(upd, ++final).av_type =
408                         AT_EXP;
409                     ULOG_ENTRY(upd, final).av_exp =
410                         (uint32_t)ent->expiration;
411                 }
412                 break;
413
414             case AT_PW_EXP:
415                 if (ent->pw_expiration >= 0) {
416                     ULOG_ENTRY_TYPE(upd, ++final).av_type =
417                         AT_PW_EXP;
418                     ULOG_ENTRY(upd, final).av_pw_exp =
419                         (uint32_t)ent->pw_expiration;
420                 }
421                 break;
422
423             case AT_LAST_SUCCESS:
424                 if (!exclude_nra && ent->last_success >= 0) {
425                     ULOG_ENTRY_TYPE(upd, ++final).av_type =
426                         AT_LAST_SUCCESS;
427                     ULOG_ENTRY(upd,
428                                final).av_last_success =
429                         (uint32_t)ent->last_success;
430                 }
431                 break;
432
433             case AT_LAST_FAILED:
434                 if (!exclude_nra && ent->last_failed >= 0) {
435                     ULOG_ENTRY_TYPE(upd, ++final).av_type =
436                         AT_LAST_FAILED;
437                     ULOG_ENTRY(upd,
438                                final).av_last_failed =
439                         (uint32_t)ent->last_failed;
440                 }
441                 break;
442
443             case AT_FAIL_AUTH_COUNT:
444                 if (!exclude_nra && ent->fail_auth_count >= (krb5_kvno)0) {
445                     ULOG_ENTRY_TYPE(upd, ++final).av_type =
446                         AT_FAIL_AUTH_COUNT;
447                     ULOG_ENTRY(upd,
448                                final).av_fail_auth_count =
449                         (uint32_t)ent->fail_auth_count;
450                 }
451                 break;
452
453             case AT_PRINC:
454                 if (ent->princ->length > 0) {
455                     ULOG_ENTRY_TYPE(upd, ++final).av_type =
456                         AT_PRINC;
457                     if ((ret = conv_princ_2ulog(ent->princ,
458                                                 upd, final, REG_PRINC))) {
459                         free(attr_types);
460                         return (ret);
461                     }
462                 }
463                 break;
464
465             case AT_KEYDATA:
466 /* BEGIN CSTYLED */
467                 if (ent->n_key_data >= 0) {
468                     ULOG_ENTRY_TYPE(upd, ++final).av_type =
469                         AT_KEYDATA;
470                     ULOG_ENTRY(upd, final).av_keydata.av_keydata_len = ent->n_key_data;
471
472                     ULOG_ENTRY(upd, final).av_keydata.av_keydata_val = malloc(ent->n_key_data * sizeof (kdbe_key_t));
473                     if (ULOG_ENTRY(upd, final).av_keydata.av_keydata_val == NULL) {
474                         free(attr_types);
475                         return (ENOMEM);
476                     }
477
478                     for (j = 0; j < ent->n_key_data; j++) {
479                         ULOG_ENTRY_KEYVAL(upd, final, j).k_ver = ent->key_data[j].key_data_ver;
480                         ULOG_ENTRY_KEYVAL(upd, final, j).k_kvno = ent->key_data[j].key_data_kvno;
481                         ULOG_ENTRY_KEYVAL(upd, final, j).k_enctype.k_enctype_len = ent->key_data[j].key_data_ver;
482                         ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_len = ent->key_data[j].key_data_ver;
483
484                         ULOG_ENTRY_KEYVAL(upd, final, j).k_enctype.k_enctype_val = malloc(ent->key_data[j].key_data_ver * sizeof(int32_t));
485                         if (ULOG_ENTRY_KEYVAL(upd, final, j).k_enctype.k_enctype_val == NULL) {
486                             free(attr_types);
487                             return (ENOMEM);
488                         }
489
490                         ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_val = malloc(ent->key_data[j].key_data_ver * sizeof(utf8str_t));
491                         if (ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_val == NULL) {
492                             free(attr_types);
493                             return (ENOMEM);
494                         }
495
496                         for (cnt = 0; cnt < ent->key_data[j].key_data_ver; cnt++) {
497                             ULOG_ENTRY_KEYVAL(upd, final, j).k_enctype.k_enctype_val[cnt] = ent->key_data[j].key_data_type[cnt];
498                             ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_val[cnt].utf8str_t_len = ent->key_data[j].key_data_length[cnt];
499                             ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_val[cnt].utf8str_t_val = malloc(ent->key_data[j].key_data_length[cnt] * sizeof (char));
500                             if (ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_val[cnt].utf8str_t_val == NULL) {
501                                 free(attr_types);
502                                 return (ENOMEM);
503                             }
504                             (void) memcpy(ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_val[cnt].utf8str_t_val, ent->key_data[j].key_data_contents[cnt], ent->key_data[j].key_data_length[cnt]);
505                         }
506                     }
507                 }
508                 break;
509
510             case AT_TL_DATA:
511                 ret = krb5_dbe_lookup_last_pwd_change(context,
512                                                       ent, &tmpint);
513                 if (ret == 0) {
514                     ULOG_ENTRY_TYPE(upd, ++final).av_type =
515                         AT_PW_LAST_CHANGE;
516                     ULOG_ENTRY(upd, final).av_pw_last_change = tmpint;
517                 }
518                 tmpint = 0;
519
520                 if(!(ret = krb5_dbe_lookup_mod_princ_data(
521                          context, ent, &tmpint, &tmpprinc))) {
522
523                     ULOG_ENTRY_TYPE(upd, ++final).av_type =
524                         AT_MOD_PRINC;
525
526                     ret = conv_princ_2ulog(tmpprinc,
527                                            upd, final, MOD_PRINC);
528                     krb5_free_principal(context, tmpprinc);
529                     if (ret) {
530                         free(attr_types);
531                         return (ret);
532                     }
533                     ULOG_ENTRY_TYPE(upd, ++final).av_type =
534                         AT_MOD_TIME;
535                     ULOG_ENTRY(upd, final).av_mod_time =
536                         tmpint;
537                 }
538
539                 newtl = ent->tl_data;
540                 while (newtl) {
541                     switch (newtl->tl_data_type) {
542                     case KRB5_TL_LAST_PWD_CHANGE:
543                     case KRB5_TL_MOD_PRINC:
544                         break;
545
546                     case KRB5_TL_KADM_DATA:
547                     default:
548                         if (kadm_data_yes == 0) {
549                             ULOG_ENTRY_TYPE(upd, ++final).av_type = AT_TL_DATA;
550                             ULOG_ENTRY(upd, final).av_tldata.av_tldata_len = 0;
551                             ULOG_ENTRY(upd, final).av_tldata.av_tldata_val = malloc(ent->n_tl_data * sizeof(kdbe_tl_t));
552
553                             if (ULOG_ENTRY(upd, final).av_tldata.av_tldata_val == NULL) {
554                                 free(attr_types);
555                                 return (ENOMEM);
556                             }
557                             kadm_data_yes = 1;
558                         }
559
560                         tmpint = ULOG_ENTRY(upd, final).av_tldata.av_tldata_len;
561                         ULOG_ENTRY(upd, final).av_tldata.av_tldata_len++;
562                         ULOG_ENTRY(upd, final).av_tldata.av_tldata_val[tmpint].tl_type = newtl->tl_data_type;
563                         ULOG_ENTRY(upd, final).av_tldata.av_tldata_val[tmpint].tl_data.tl_data_len = newtl->tl_data_length;
564                         ULOG_ENTRY(upd, final).av_tldata.av_tldata_val[tmpint].tl_data.tl_data_val = malloc(newtl->tl_data_length * sizeof (char));
565                         if (ULOG_ENTRY(upd, final).av_tldata.av_tldata_val[tmpint].tl_data.tl_data_val == NULL) {
566                             free(attr_types);
567                             return (ENOMEM);
568                         }
569                         (void) memcpy(ULOG_ENTRY(upd, final).av_tldata.av_tldata_val[tmpint].tl_data.tl_data_val, newtl->tl_data_contents, newtl->tl_data_length);
570                         break;
571                     }
572                     newtl = newtl->tl_data_next;
573                 }
574                 break;
575 /* END CSTYLED */
576
577             case AT_LEN:
578                 if (ent->len >= 0) {
579                     ULOG_ENTRY_TYPE(upd, ++final).av_type =
580                         AT_LEN;
581                     ULOG_ENTRY(upd, final).av_len =
582                         (int16_t)ent->len;
583                 }
584                 break;
585
586             default:
587                 break;
588             }
589
590         }
591
592         free(attr_types);
593
594         /*
595          * Update len field in kdb_update
596          */
597         upd->kdb_update.kdbe_t_len = ++final;
598
599         /*
600          * Bump up to next struct
601          */
602         upd++;
603         ent++;
604     }
605     return (0);
606 }
607
608 /*
609  * This routine converts one or more update log (ulog) entries into
610  * kerberos db2 records. Required memory should be allocated
611  * for the db2 records (pointed to by krb5_db_entry *ent), prior
612  * to calling this routine.
613  */
614 krb5_error_code
615 ulog_conv_2dbentry(krb5_context context, krb5_db_entry *entries,
616                    kdb_incr_update_t *updates,
617                    int nentries)
618 {
619     int k;
620     krb5_db_entry *ent;
621     kdb_incr_update_t *upd;
622     int slave;
623
624     if ((updates == NULL) || (entries == NULL))
625         return (KRB5KRB_ERR_GENERIC);
626
627     ent = entries;
628     upd = updates;
629
630     slave = (context->kdblog_context != NULL) &&
631             (context->kdblog_context->iproprole == IPROP_SLAVE);
632
633     for (k = 0; k < nentries; k++) {
634         krb5_principal mod_princ = NULL;
635         int i, j, cnt = 0, mod_time = 0, nattrs, nprincs = 0;
636         krb5_principal dbprinc;
637         char *dbprincstr = NULL;
638
639         krb5_tl_data *newtl = NULL;
640         krb5_error_code ret;
641         unsigned int more;
642         unsigned int prev_n_keys = 0;
643
644         /*
645          * If the ulog entry represents a DELETE update,
646          * just skip to the next entry.
647          */
648         if (upd->kdb_deleted == TRUE)
649             goto next;
650
651         /*
652          * Store the no. of changed attributes in nattrs
653          */
654         nattrs = upd->kdb_update.kdbe_t_len;
655
656         dbprincstr = malloc((upd->kdb_princ_name.utf8str_t_len + 1)
657                             * sizeof (char));
658         if (dbprincstr == NULL)
659             return (ENOMEM);
660         strncpy(dbprincstr, (char *)upd->kdb_princ_name.utf8str_t_val,
661                 upd->kdb_princ_name.utf8str_t_len);
662         dbprincstr[upd->kdb_princ_name.utf8str_t_len] = 0;
663
664         ret = krb5_parse_name(context, dbprincstr, &dbprinc);
665         free(dbprincstr);
666         if (ret)
667             return (ret);
668
669         ret = krb5_db_get_principal(context, dbprinc, ent, &nprincs,
670                                     &more);
671         krb5_free_principal(context, dbprinc);
672         if (ret)
673             return (ret);
674
675         /*
676          * Set ent->n_tl_data = 0 initially, if this is an ADD update
677          */
678         if (nprincs == 0)
679             ent->n_tl_data = 0;
680
681         for (i = 0; i < nattrs; i++) {
682             krb5_principal tmpprinc = NULL;
683
684 #define u (ULOG_ENTRY(upd, i))
685             switch (ULOG_ENTRY_TYPE(upd, i).av_type) {
686             case AT_ATTRFLAGS:
687                 ent->attributes = (krb5_flags) u.av_attrflags;
688                 break;
689
690             case AT_MAX_LIFE:
691                 ent->max_life = (krb5_deltat) u.av_max_life;
692                 break;
693
694             case AT_MAX_RENEW_LIFE:
695                 ent->max_renewable_life = (krb5_deltat) u.av_max_renew_life;
696                 break;
697
698             case AT_EXP:
699                 ent->expiration = (krb5_timestamp) u.av_exp;
700                 break;
701
702             case AT_PW_EXP:
703                 ent->pw_expiration = (krb5_timestamp) u.av_pw_exp;
704                 break;
705
706             case AT_LAST_SUCCESS:
707                 if (!slave)
708                     ent->last_success = (krb5_timestamp) u.av_last_success;
709                 break;
710
711             case AT_LAST_FAILED:
712                 if (!slave)
713                     ent->last_failed = (krb5_timestamp) u.av_last_failed;
714                 break;
715
716             case AT_FAIL_AUTH_COUNT:
717                 if (!slave)
718                     ent->fail_auth_count = (krb5_kvno) u.av_fail_auth_count;
719                 break;
720
721             case AT_PRINC:
722                 tmpprinc = conv_princ_2db(context, &u.av_princ);
723                 if (tmpprinc == NULL)
724                     return ENOMEM;
725                 if (nprincs)
726                     krb5_free_principal(context, ent->princ);
727                 ent->princ = tmpprinc;
728                 break;
729
730             case AT_KEYDATA:
731                 if (nprincs != 0)
732                     prev_n_keys = ent->n_key_data;
733                 else
734                     prev_n_keys = 0;
735                 ent->n_key_data = (krb5_int16)u.av_keydata.av_keydata_len;
736                 if (nprincs == 0)
737                     ent->key_data = NULL;
738
739                 ent->key_data = (krb5_key_data *)realloc(ent->key_data,
740                                                          (ent->n_key_data *
741                                                           sizeof (krb5_key_data)));
742                 /* XXX Memory leak: Old key data in
743                    records eliminated by resizing to
744                    smaller size.  */
745                 if (ent->key_data == NULL)
746                     /* XXX Memory leak: old storage.  */
747                     return (ENOMEM);
748
749 /* BEGIN CSTYLED */
750                 for (j = prev_n_keys; j < ent->n_key_data; j++) {
751                     for (cnt = 0; cnt < 2; cnt++) {
752                         ent->key_data[j].key_data_contents[cnt] = NULL;
753                     }
754                 }
755                 for (j = 0; j < ent->n_key_data; j++) {
756                     krb5_key_data *kp = &ent->key_data[j];
757                     kdbe_key_t *kv = &ULOG_ENTRY_KEYVAL(upd, i, j);
758                     kp->key_data_ver = (krb5_int16)kv->k_ver;
759                     kp->key_data_kvno = (krb5_int16)kv->k_kvno;
760                     if (kp->key_data_ver > 2) {
761                         return EINVAL; /* XXX ? */
762                     }
763
764                     for (cnt = 0; cnt < kp->key_data_ver; cnt++) {
765                         void *newptr;
766                         kp->key_data_type[cnt] =  (krb5_int16)kv->k_enctype.k_enctype_val[cnt];
767                         kp->key_data_length[cnt] = (krb5_int16)kv->k_contents.k_contents_val[cnt].utf8str_t_len;
768                         newptr = realloc(kp->key_data_contents[cnt],
769                                          kp->key_data_length[cnt]);
770                         if (newptr == NULL)
771                             return ENOMEM;
772                         kp->key_data_contents[cnt] = newptr;
773
774                         (void) memset(kp->key_data_contents[cnt], 0,
775                                       kp->key_data_length[cnt]);
776                         (void) memcpy(kp->key_data_contents[cnt],
777                                       kv->k_contents.k_contents_val[cnt].utf8str_t_val,
778                                       kp->key_data_length[cnt]);
779                     }
780                 }
781                 break;
782
783             case AT_TL_DATA: {
784                 int t;
785
786                 cnt = u.av_tldata.av_tldata_len;
787                 newtl = calloc(cnt, sizeof (krb5_tl_data));
788                 if (newtl == NULL)
789                     return (ENOMEM);
790
791                 for (j = 0, t = 0; j < cnt; j++) {
792                     newtl[t].tl_data_type = (krb5_int16)u.av_tldata.av_tldata_val[j].tl_type;
793                     newtl[t].tl_data_length = (krb5_int16)u.av_tldata.av_tldata_val[j].tl_data.tl_data_len;
794                     newtl[t].tl_data_contents = malloc(newtl[t].tl_data_length * sizeof (krb5_octet));
795                     if (newtl[t].tl_data_contents == NULL)
796                         /* XXX Memory leak: newtl
797                            and previously
798                            allocated elements.  */
799                         return (ENOMEM);
800
801                     (void) memcpy(newtl[t].tl_data_contents, u.av_tldata.av_tldata_val[t].tl_data.tl_data_val, newtl[t].tl_data_length);
802                     newtl[t].tl_data_next = NULL;
803                     if (t > 0)
804                         newtl[t - 1].tl_data_next = &newtl[t];
805                     t++;
806                 }
807
808                 if ((ret = krb5_dbe_update_tl_data(context, ent, newtl)))
809                     return (ret);
810                 for (j = 0; j < t; j++)
811                     if (newtl[j].tl_data_contents) {
812                         free(newtl[j].tl_data_contents);
813                         newtl[j].tl_data_contents = NULL;
814                     }
815                 if (newtl) {
816                     free(newtl);
817                     newtl = NULL;
818                 }
819                 break;
820 /* END CSTYLED */
821             }
822             case AT_PW_LAST_CHANGE:
823                 if ((ret = krb5_dbe_update_last_pwd_change(context, ent,
824                                                            u.av_pw_last_change)))
825                     return (ret);
826                 break;
827
828             case AT_MOD_PRINC:
829                 tmpprinc = conv_princ_2db(context, &u.av_mod_princ);
830                 if (tmpprinc == NULL)
831                     return ENOMEM;
832                 mod_princ = tmpprinc;
833                 break;
834
835             case AT_MOD_TIME:
836                 mod_time = u.av_mod_time;
837                 break;
838
839             case AT_LEN:
840                 ent->len = (krb5_int16) u.av_len;
841                 break;
842
843             default:
844                 break;
845             }
846 #undef u
847         }
848
849         /*
850          * process mod_princ_data request
851          */
852         if (mod_time && mod_princ) {
853             ret = krb5_dbe_update_mod_princ_data(context, ent,
854                                                  mod_time, mod_princ);
855             krb5_free_principal(context, mod_princ);
856             mod_princ = NULL;
857             if (ret)
858                 return (ret);
859         }
860
861     next:
862         /*
863          * Bump up to next struct
864          */
865         upd++;
866         ent++;
867     }
868     return (0);
869 }
870
871
872
873 /*
874  * This routine frees up memory associated with the bunched ulog entries.
875  */
876 void
877 ulog_free_entries(kdb_incr_update_t *updates, int no_of_updates)
878 {
879
880     kdb_incr_update_t *upd;
881     int i, j, k, cnt;
882
883     if (updates == NULL)
884         return;
885
886     upd = updates;
887
888     /*
889      * Loop thru each ulog entry
890      */
891     for (cnt = 0; cnt < no_of_updates; cnt++) {
892
893         /*
894          * ulog entry - kdb_princ_name
895          */
896         free(upd->kdb_princ_name.utf8str_t_val);
897
898 /* BEGIN CSTYLED */
899
900         /*
901          * ulog entry - kdb_kdcs_seen_by
902          */
903         if (upd->kdb_kdcs_seen_by.kdb_kdcs_seen_by_val) {
904             for (i = 0; i < upd->kdb_kdcs_seen_by.kdb_kdcs_seen_by_len; i++)
905                 free(upd->kdb_kdcs_seen_by.kdb_kdcs_seen_by_val[i].utf8str_t_val);
906             free(upd->kdb_kdcs_seen_by.kdb_kdcs_seen_by_val);
907         }
908
909         /*
910          * ulog entry - kdb_futures
911          */
912         free(upd->kdb_futures.kdb_futures_val);
913
914         /*
915          * ulog entry - kdb_update
916          */
917         if (upd->kdb_update.kdbe_t_val) {
918             /*
919              * Loop thru all the attributes and free up stuff
920              */
921             for (i = 0; i < upd->kdb_update.kdbe_t_len; i++) {
922
923                 /*
924                  * Free av_key_data
925                  */
926                 if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_KEYDATA) && ULOG_ENTRY(upd, i).av_keydata.av_keydata_val) {
927
928                     for (j = 0; j < ULOG_ENTRY(upd, i).av_keydata.av_keydata_len; j++) {
929                         free(ULOG_ENTRY_KEYVAL(upd, i, j).k_enctype.k_enctype_val);
930                         if (ULOG_ENTRY_KEYVAL(upd, i, j).k_contents.k_contents_val) {
931                             for (k = 0; k < ULOG_ENTRY_KEYVAL(upd, i, j).k_ver; k++) {
932                                 free(ULOG_ENTRY_KEYVAL(upd, i, j).k_contents.k_contents_val[k].utf8str_t_val);
933                             }
934                             free(ULOG_ENTRY_KEYVAL(upd, i, j).k_contents.k_contents_val);
935                         }
936                     }
937                     free(ULOG_ENTRY(upd, i).av_keydata.av_keydata_val);
938                 }
939
940
941                 /*
942                  * Free av_tl_data
943                  */
944                 if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_TL_DATA) && ULOG_ENTRY(upd, i).av_tldata.av_tldata_val) {
945                     for (j = 0; j < ULOG_ENTRY(upd, i).av_tldata.av_tldata_len; j++) {
946                         free(ULOG_ENTRY(upd, i).av_tldata.av_tldata_val[j].tl_data.tl_data_val);
947                     }
948                     free(ULOG_ENTRY(upd, i).av_tldata.av_tldata_val);
949                 }
950
951                 /*
952                  * Free av_princ
953                  */
954                 if (ULOG_ENTRY_TYPE(upd, i).av_type == AT_PRINC) {
955                     free(ULOG_ENTRY(upd, i).av_princ.k_realm.utf8str_t_val);
956                     if (ULOG_ENTRY(upd, i).av_princ.k_components.k_components_val) {
957                         for (j = 0; j < ULOG_ENTRY(upd, i).av_princ.k_components.k_components_len; j++) {
958                             free(ULOG_ENTRY_PRINC(upd, i, j).k_data.utf8str_t_val);
959                         }
960                         free(ULOG_ENTRY(upd, i).av_princ.k_components.k_components_val);
961                     }
962                 }
963
964                 /*
965                  * Free av_mod_princ
966                  */
967                 if (ULOG_ENTRY_TYPE(upd, i).av_type == AT_MOD_PRINC) {
968                     free(ULOG_ENTRY(upd, i).av_mod_princ.k_realm.utf8str_t_val);
969                     if (ULOG_ENTRY(upd, i).av_mod_princ.k_components.k_components_val) {
970                         for (j = 0; j < ULOG_ENTRY(upd, i).av_mod_princ.k_components.k_components_len; j++) {
971                             free(ULOG_ENTRY_MOD_PRINC(upd, i, j).k_data.utf8str_t_val);
972                         }
973                         free(ULOG_ENTRY(upd, i).av_mod_princ.k_components.k_components_val);
974                     }
975                 }
976
977                 /*
978                  * Free av_mod_where
979                  */
980                 if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_MOD_WHERE) && ULOG_ENTRY(upd, i).av_mod_where.utf8str_t_val)
981                     free(ULOG_ENTRY(upd, i).av_mod_where.utf8str_t_val);
982
983                 /*
984                  * Free av_pw_policy
985                  */
986                 if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_PW_POLICY) && ULOG_ENTRY(upd, i).av_pw_policy.utf8str_t_val)
987                     free(ULOG_ENTRY(upd, i).av_pw_policy.utf8str_t_val);
988
989                 /* 
990                  * XXX: Free av_pw_hist
991                  *
992                  * For now, we just free the pointer
993                  * to av_pw_hist_val, since we aren't
994                  * populating this union member in
995                  * the conv api function(s) anyways.
996                  */
997                 if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_PW_HIST) && ULOG_ENTRY(upd, i).av_pw_hist.av_pw_hist_val)
998                     free(ULOG_ENTRY(upd, i).av_pw_hist.av_pw_hist_val);
999
1000             }
1001
1002             /*
1003              * Free up the pointer to kdbe_t_val
1004              */
1005             free(upd->kdb_update.kdbe_t_val);
1006         }
1007
1008 /* END CSTYLED */
1009
1010         /*
1011          * Bump up to next struct
1012          */
1013         upd++;
1014     }
1015
1016
1017     /*
1018      * Finally, free up the pointer to the bunched ulog entries
1019      */
1020     free(updates);
1021 }