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