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