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