Home | History | Annotate | Download | only in kdb
      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