xref: /illumos-gate/usr/src/lib/krb5/kdb/kdb_convert.c (revision 4f364e7c95ee7fd9d5bbeddc1940e92405bb0e72)
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 
32 typedef 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  */
43 static void
44 find_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 
142 static int
143 data_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  */
159 static krb5_error_code
160 conv_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  */
222 static void
223 set_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  */
241 static krb5_principal
242 conv_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;
279 error:
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  */
289 krb5_error_code
290 ulog_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  */
599 krb5_error_code
600 ulog_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 
839 next:
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  */
854 void
855 ulog_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