/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* #pragma ident "@(#)kdb_convert.c 1.3 05/01/05 SMI" */
/*
* This file contains api's for conversion of the kdb_incr_update_t
* struct(s) into krb5_db_entry struct(s) and vice-versa.
*/
#include <sys/types.h>
#include <com_err.h>
#include <locale.h>
#include <errno.h>
#include <iprop_hdr.h>
#include "iprop.h"
#include <k5-int.h>
#include <kdb.h>
#include <kdb_log.h>
/* BEGIN CSTYLED */
#define ULOG_ENTRY_TYPE(upd, i) ((kdb_incr_update_t *)upd)->kdb_update.kdbe_t_val[i]
#define ULOG_ENTRY(upd, i) ((kdb_incr_update_t *)upd)->kdb_update.kdbe_t_val[i].kdbe_val_t_u
#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]
#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]
#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]
/* END CSTYLED */
typedef enum {
REG_PRINC = 0,
MOD_PRINC = 1
} princ_type;
/*
* This routine tracks the krb5_db_entry fields that have been modified
* (by comparing it to the db_entry currently present in principal.db)
* in the update.
*/
static void
find_changed_attrs(krb5_db_entry *current, krb5_db_entry *new,
krb5_boolean exclude_nra,
kdbe_attr_type_t *attrs, int *nattrs)
{
int i = 0, j = 0;
krb5_tl_data *first, *second;
if (current->attributes != new->attributes)
attrs[i++] = AT_ATTRFLAGS;
if (current->max_life != new->max_life)
attrs[i++] = AT_MAX_LIFE;
if (current->max_renewable_life != new->max_renewable_life)
attrs[i++] = AT_MAX_RENEW_LIFE;
if (current->expiration != new->expiration)
attrs[i++] = AT_EXP;
if (current->pw_expiration != new->pw_expiration)
attrs[i++] = AT_PW_EXP;
if (!exclude_nra) {
if (current->last_success != new->last_success)
attrs[i++] = AT_LAST_SUCCESS;
if (current->last_failed != new->last_failed)
attrs[i++] = AT_LAST_FAILED;
if (current->fail_auth_count != new->fail_auth_count)
attrs[i++] = AT_FAIL_AUTH_COUNT;
}
if ((current->princ->type == new->princ->type) &&
(current->princ->length == new->princ->length)) {
if ((current->princ->realm.length ==
new->princ->realm.length) &&
strncmp(current->princ->realm.data,
new->princ->realm.data,
current->princ->realm.length)) {
for (j = 0; j < current->princ->length; j++) {
if ((current->princ->data[j].data != NULL) &&
(strncmp(current->princ->data[j].data,
new->princ->data[j].data,
current->princ->data[j].length))) {
attrs[i++] = AT_PRINC;
break;
}
}
} else {
attrs[i++] = AT_PRINC;
}
} else {
attrs[i++] = AT_PRINC;
}
if (current->n_key_data == new->n_key_data) {
/* Assuming key ordering is the same in new & current */
for (j = 0; j < new->n_key_data; j++) {
if (current->key_data[j].key_data_kvno !=
new->key_data[j].key_data_kvno) {
attrs[i++] = AT_KEYDATA;
break;
}
}
} else {
attrs[i++] = AT_KEYDATA;
}
if (current->n_tl_data == new->n_tl_data) {
/* Assuming we preserve the TL_DATA ordering between updates */
for (first = current->tl_data, second = new->tl_data;
first; first = first->tl_data_next,
second = second->tl_data_next) {
if ((first->tl_data_length == second->tl_data_length) &&
(first->tl_data_type == second->tl_data_type)) {
if ((memcmp((char *)first->tl_data_contents,
(char *)second->tl_data_contents,
first->tl_data_length)) != 0) {
attrs[i++] = AT_TL_DATA;
break;
}
} else {
attrs[i++] = AT_TL_DATA;
break;
}
}
} else {
attrs[i++] = AT_TL_DATA;
}
if (current->len != new->len)
attrs[i++] = AT_LEN;
/*
* Store the no. of (possibly :)) changed attributes
*/
*nattrs = i;
}
/*
*/
static int
data_to_utf8str(utf8str_t *u, krb5_data d)
{
u->utf8str_t_len = d.length;
if (d.data) {
u->utf8str_t_val = malloc(d.length);
if (u->utf8str_t_val == NULL)
return -1;
memcpy(u->utf8str_t_val, d.data, d.length);
} else
u->utf8str_t_val = NULL;
return 0;
}
/*
* Converts the krb5_principal struct from db2 to ulog format.
*/
static krb5_error_code
conv_princ_2ulog(krb5_principal princ, kdb_incr_update_t *upd,
int cnt, princ_type tp)
{
int i = 0;
kdbe_princ_t *p;
kdbe_data_t *components;
if ((upd == NULL) || !princ)
return (KRB5KRB_ERR_GENERIC);
switch (tp) {
case REG_PRINC:
case MOD_PRINC:
p = &ULOG_ENTRY(upd, cnt).av_princ; /* or av_mod_princ */
p->k_nametype = (int32_t)princ->type;
if (data_to_utf8str(&p->k_realm, princ->realm) < 0) {
return ENOMEM;
}
p->k_components.k_components_len = princ->length;
p->k_components.k_components_val = components
= malloc(princ->length * sizeof (kdbe_data_t));
if (p->k_components.k_components_val == NULL) {
free(p->k_realm.utf8str_t_val);
p->k_realm.utf8str_t_val = NULL;
return (ENOMEM);
}
memset(components, 0, princ->length * sizeof(kdbe_data_t));
for (i = 0; i < princ->length; i++)
components[i].k_data.utf8str_t_val = NULL;
for (i = 0; i < princ->length; i++) {
components[i].k_magic = princ->data[i].magic;
if (data_to_utf8str(&components[i].k_data, princ->data[i]) < 0) {
int j;
for (j = 0; j < i; j++) {
free(components[j].k_data.utf8str_t_val);
components[j].k_data.utf8str_t_val = NULL;
}
free(components);
p->k_components.k_components_val = NULL;
free(p->k_realm.utf8str_t_val);
p->k_realm.utf8str_t_val = NULL;
return ENOMEM;
}
}
break;
default:
break;
}
return (0);
}
/*
* Copies a UTF-8 string from ulog to a krb5_data object, which may
* already have allocated storage associated with it.
*
* Maybe a return value should indicate success/failure?
*/
static void
set_from_utf8str(krb5_data *d, utf8str_t u)
{
if (u.utf8str_t_len > INT_MAX-1 || u.utf8str_t_len >= SIZE_MAX-1) {
d->data = NULL;
return;
}
d->length = u.utf8str_t_len;
d->data = malloc(d->length + 1);
if (d->data == NULL)
return;
if (d->length) /* Pointer may be null if length = 0. */
strncpy(d->data, u.utf8str_t_val, d->length);
d->data[d->length] = 0;
}
/*
* Converts the krb5_principal struct from ulog to db2 format.
*/
static krb5_principal
conv_princ_2db(krb5_context context, kdbe_princ_t *kdbe_princ)
{
int i;
krb5_principal princ;
kdbe_data_t *components;
princ = calloc(1, sizeof (krb5_principal_data));
if (princ == NULL) {
return NULL;
}
princ->length = 0;
princ->data = NULL;
components = kdbe_princ->k_components.k_components_val;
princ->type = (krb5_int32) kdbe_princ->k_nametype;
princ->realm.data = NULL;
set_from_utf8str(&princ->realm, kdbe_princ->k_realm);
if (princ->realm.data == NULL)
goto error;
princ->data = calloc(kdbe_princ->k_components.k_components_len,
sizeof (krb5_data));
if (princ->data == NULL)
goto error;
for (i = 0; i < kdbe_princ->k_components.k_components_len; i++)
princ->data[i].data = NULL;
princ->length = (krb5_int32)kdbe_princ->k_components.k_components_len;
for (i = 0; i < princ->length; i++) {
princ->data[i].magic = components[i].k_magic;
set_from_utf8str(&princ->data[i], components[i].k_data);
if (princ->data[i].data == NULL)
goto error;
}
return princ;
error:
krb5_free_principal(context, princ);
return NULL;
}
/*
* This routine converts one or more krb5 db2 records into update
* log (ulog) entry format. Space for the update log entries should
* be allocated prior to invocation of this routine.
*/
krb5_error_code
ulog_conv_2logentry(krb5_context context, krb5_db_entry *entries,
kdb_incr_update_t *updates,
int nentries)
{
int i, j, k, cnt, final, nattrs, tmpint, nprincs;
unsigned int more;
krb5_principal tmpprinc;
krb5_tl_data *newtl;
krb5_db_entry curr;
krb5_error_code ret;
kdbe_attr_type_t *attr_types;
kdb_incr_update_t *upd;
krb5_db_entry *ent;
int kadm_data_yes;
/* always exclude non-replicated attributes, for now */
krb5_boolean exclude_nra = TRUE;
if ((updates == NULL) || (entries == NULL))
return (KRB5KRB_ERR_GENERIC);
upd = updates;
ent = entries;
for (k = 0; k < nentries; k++) {
nprincs = nattrs = tmpint = 0;
final = -1;
kadm_data_yes = 0;
attr_types = NULL;
/*
* XXX we rely on the good behaviour of the database not to
* exceed this limit.
*/
if ((upd->kdb_update.kdbe_t_val = (kdbe_val_t *)
malloc(MAXENTRY_SIZE)) == NULL) {
return (ENOMEM);
}
/*
* Find out which attrs have been modified
*/
if ((attr_types = (kdbe_attr_type_t *)malloc(
sizeof (kdbe_attr_type_t) * MAXATTRS_SIZE))
== NULL) {
return (ENOMEM);
}
if ((ret = krb5_db_get_principal(context, ent->princ, &curr,
&nprincs, &more))) {
free(attr_types);
return (ret);
}
if (nprincs == 0) {
/*
* This is a new entry to the database, hence will
* include all the attribute-value pairs
*
* We leave out the TL_DATA types which we model as
* attrs in kdbe_attr_type_t, since listing AT_TL_DATA
* encompasses these other types-turned-attributes
*
* So, we do *NOT* consider AT_MOD_PRINC, AT_MOD_TIME,
* AT_MOD_WHERE, AT_PW_LAST_CHANGE, AT_PW_POLICY,
* AT_PW_POLICY_SWITCH, AT_PW_HIST_KVNO and AT_PW_HIST,
* totalling 8 attrs.
*/
while (nattrs < MAXATTRS_SIZE - 8) {
attr_types[nattrs] = nattrs;
nattrs++;
}
} else {
find_changed_attrs(&curr, ent, exclude_nra, attr_types, &nattrs);
krb5_db_free_principal(context, &curr, nprincs);
}
for (i = 0; i < nattrs; i++) {
switch (attr_types[i]) {
case AT_ATTRFLAGS:
if (ent->attributes >= 0) {
ULOG_ENTRY_TYPE(upd, ++final).av_type =
AT_ATTRFLAGS;
ULOG_ENTRY(upd, final).av_attrflags =
(uint32_t)ent->attributes;
}
break;
case AT_MAX_LIFE:
if (ent->max_life >= 0) {
ULOG_ENTRY_TYPE(upd, ++final).av_type =
AT_MAX_LIFE;
ULOG_ENTRY(upd, final).av_max_life =
(uint32_t)ent->max_life;
}
break;
case AT_MAX_RENEW_LIFE:
if (ent->max_renewable_life >= 0) {
ULOG_ENTRY_TYPE(upd, ++final).av_type =
AT_MAX_RENEW_LIFE;
ULOG_ENTRY(upd,
final).av_max_renew_life =
(uint32_t)ent->max_renewable_life;
}
break;
case AT_EXP:
if (ent->expiration >= 0) {
ULOG_ENTRY_TYPE(upd, ++final).av_type =
AT_EXP;
ULOG_ENTRY(upd, final).av_exp =
(uint32_t)ent->expiration;
}
break;
case AT_PW_EXP:
if (ent->pw_expiration >= 0) {
ULOG_ENTRY_TYPE(upd, ++final).av_type =
AT_PW_EXP;
ULOG_ENTRY(upd, final).av_pw_exp =
(uint32_t)ent->pw_expiration;
}
break;
case AT_LAST_SUCCESS:
if (!exclude_nra && ent->last_success >= 0) {
ULOG_ENTRY_TYPE(upd, ++final).av_type =
AT_LAST_SUCCESS;
ULOG_ENTRY(upd,
final).av_last_success =
(uint32_t)ent->last_success;
}
break;
case AT_LAST_FAILED:
if (!exclude_nra && ent->last_failed >= 0) {
ULOG_ENTRY_TYPE(upd, ++final).av_type =
AT_LAST_FAILED;
ULOG_ENTRY(upd,
final).av_last_failed =
(uint32_t)ent->last_failed;
}
break;
case AT_FAIL_AUTH_COUNT:
if (!exclude_nra && ent->fail_auth_count >= (krb5_kvno)0) {
ULOG_ENTRY_TYPE(upd, ++final).av_type =
AT_FAIL_AUTH_COUNT;
ULOG_ENTRY(upd,
final).av_fail_auth_count =
(uint32_t)ent->fail_auth_count;
}
break;
case AT_PRINC:
if (ent->princ->length > 0) {
ULOG_ENTRY_TYPE(upd, ++final).av_type =
AT_PRINC;
if ((ret = conv_princ_2ulog(ent->princ,
upd, final, REG_PRINC))) {
free(attr_types);
return (ret);
}
}
break;
case AT_KEYDATA:
/* BEGIN CSTYLED */
if (ent->n_key_data >= 0) {
ULOG_ENTRY_TYPE(upd, ++final).av_type =
AT_KEYDATA;
ULOG_ENTRY(upd, final).av_keydata.av_keydata_len = ent->n_key_data;
ULOG_ENTRY(upd, final).av_keydata.av_keydata_val = malloc(ent->n_key_data * sizeof (kdbe_key_t));
if (ULOG_ENTRY(upd, final).av_keydata.av_keydata_val == NULL) {
free(attr_types);
return (ENOMEM);
}
for (j = 0; j < ent->n_key_data; j++) {
ULOG_ENTRY_KEYVAL(upd, final, j).k_ver = ent->key_data[j].key_data_ver;
ULOG_ENTRY_KEYVAL(upd, final, j).k_kvno = ent->key_data[j].key_data_kvno;
ULOG_ENTRY_KEYVAL(upd, final, j).k_enctype.k_enctype_len = ent->key_data[j].key_data_ver;
ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_len = ent->key_data[j].key_data_ver;
ULOG_ENTRY_KEYVAL(upd, final, j).k_enctype.k_enctype_val = malloc(ent->key_data[j].key_data_ver * sizeof(int32_t));
if (ULOG_ENTRY_KEYVAL(upd, final, j).k_enctype.k_enctype_val == NULL) {
free(attr_types);
return (ENOMEM);
}
ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_val = malloc(ent->key_data[j].key_data_ver * sizeof(utf8str_t));
if (ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_val == NULL) {
free(attr_types);
return (ENOMEM);
}
for (cnt = 0; cnt < ent->key_data[j].key_data_ver; cnt++) {
ULOG_ENTRY_KEYVAL(upd, final, j).k_enctype.k_enctype_val[cnt] = ent->key_data[j].key_data_type[cnt];
ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_val[cnt].utf8str_t_len = ent->key_data[j].key_data_length[cnt];
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));
if (ULOG_ENTRY_KEYVAL(upd, final, j).k_contents.k_contents_val[cnt].utf8str_t_val == NULL) {
free(attr_types);
return (ENOMEM);
}
(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]);
}
}
}
break;
case AT_TL_DATA:
ret = krb5_dbe_lookup_last_pwd_change(context,
ent, &tmpint);
if (ret == 0) {
ULOG_ENTRY_TYPE(upd, ++final).av_type =
AT_PW_LAST_CHANGE;
ULOG_ENTRY(upd, final).av_pw_last_change = tmpint;
}
tmpint = 0;
if(!(ret = krb5_dbe_lookup_mod_princ_data(
context, ent, &tmpint, &tmpprinc))) {
ULOG_ENTRY_TYPE(upd, ++final).av_type =
AT_MOD_PRINC;
ret = conv_princ_2ulog(tmpprinc,
upd, final, MOD_PRINC);
krb5_free_principal(context, tmpprinc);
if (ret) {
free(attr_types);
return (ret);
}
ULOG_ENTRY_TYPE(upd, ++final).av_type =
AT_MOD_TIME;
ULOG_ENTRY(upd, final).av_mod_time =
tmpint;
}
newtl = ent->tl_data;
while (newtl) {
switch (newtl->tl_data_type) {
case KRB5_TL_LAST_PWD_CHANGE:
case KRB5_TL_MOD_PRINC:
break;
case KRB5_TL_KADM_DATA:
default:
if (kadm_data_yes == 0) {
ULOG_ENTRY_TYPE(upd, ++final).av_type = AT_TL_DATA;
ULOG_ENTRY(upd, final).av_tldata.av_tldata_len = 0;
ULOG_ENTRY(upd, final).av_tldata.av_tldata_val = malloc(ent->n_tl_data * sizeof(kdbe_tl_t));
if (ULOG_ENTRY(upd, final).av_tldata.av_tldata_val == NULL) {
free(attr_types);
return (ENOMEM);
}
kadm_data_yes = 1;
}
tmpint = ULOG_ENTRY(upd, final).av_tldata.av_tldata_len;
ULOG_ENTRY(upd, final).av_tldata.av_tldata_len++;
ULOG_ENTRY(upd, final).av_tldata.av_tldata_val[tmpint].tl_type = newtl->tl_data_type;
ULOG_ENTRY(upd, final).av_tldata.av_tldata_val[tmpint].tl_data.tl_data_len = newtl->tl_data_length;
ULOG_ENTRY(upd, final).av_tldata.av_tldata_val[tmpint].tl_data.tl_data_val = malloc(newtl->tl_data_length * sizeof (char));
if (ULOG_ENTRY(upd, final).av_tldata.av_tldata_val[tmpint].tl_data.tl_data_val == NULL) {
free(attr_types);
return (ENOMEM);
}
(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);
break;
}
newtl = newtl->tl_data_next;
}
break;
/* END CSTYLED */
case AT_LEN:
#if 0 /* Solaris Kerberos - cc warning - always true */
if (ent->len >= 0) {
#endif
ULOG_ENTRY_TYPE(upd, ++final).av_type =
AT_LEN;
ULOG_ENTRY(upd, final).av_len =
(int16_t)ent->len;
#if 0 /* Solaris Kerberos */
}
#endif
break;
default:
break;
}
}
free(attr_types);
/*
* Update len field in kdb_update
*/
upd->kdb_update.kdbe_t_len = ++final;
/*
* Bump up to next struct
*/
upd++;
ent++;
}
return (0);
}
/*
* This routine converts one or more update log (ulog) entries into
* kerberos db2 records. Required memory should be allocated
* for the db2 records (pointed to by krb5_db_entry *ent), prior
* to calling this routine.
*/
krb5_error_code
ulog_conv_2dbentry(krb5_context context, krb5_db_entry *entries,
kdb_incr_update_t *updates,
int nentries)
{
int k;
krb5_db_entry *ent;
kdb_incr_update_t *upd;
int slave;
if ((updates == NULL) || (entries == NULL))
return (KRB5KRB_ERR_GENERIC);
ent = entries;
upd = updates;
slave = (context->kdblog_context != NULL) &&
(context->kdblog_context->iproprole == IPROP_SLAVE);
for (k = 0; k < nentries; k++) {
krb5_principal mod_princ = NULL;
int i, j, cnt = 0, mod_time = 0, nattrs, nprincs = 0;
krb5_principal dbprinc;
char *dbprincstr = NULL;
krb5_tl_data *newtl = NULL;
krb5_error_code ret;
unsigned int more;
unsigned int prev_n_keys = 0;
/*
* If the ulog entry represents a DELETE update,
* just skip to the next entry.
*/
if (upd->kdb_deleted == TRUE)
goto next;
/*
* Store the no. of changed attributes in nattrs
*/
nattrs = upd->kdb_update.kdbe_t_len;
dbprincstr = malloc((upd->kdb_princ_name.utf8str_t_len + 1)
* sizeof (char));
if (dbprincstr == NULL)
return (ENOMEM);
strncpy(dbprincstr, (char *)upd->kdb_princ_name.utf8str_t_val,
upd->kdb_princ_name.utf8str_t_len);
dbprincstr[upd->kdb_princ_name.utf8str_t_len] = 0;
ret = krb5_parse_name(context, dbprincstr, &dbprinc);
free(dbprincstr);
if (ret)
return (ret);
ret = krb5_db_get_principal(context, dbprinc, ent, &nprincs,
&more);
krb5_free_principal(context, dbprinc);
if (ret)
return (ret);
/*
* Set ent->n_tl_data = 0 initially, if this is an ADD update
*/
if (nprincs == 0)
ent->n_tl_data = 0;
for (i = 0; i < nattrs; i++) {
krb5_principal tmpprinc = NULL;
#define u (ULOG_ENTRY(upd, i))
switch (ULOG_ENTRY_TYPE(upd, i).av_type) {
case AT_ATTRFLAGS:
ent->attributes = (krb5_flags) u.av_attrflags;
break;
case AT_MAX_LIFE:
ent->max_life = (krb5_deltat) u.av_max_life;
break;
case AT_MAX_RENEW_LIFE:
ent->max_renewable_life = (krb5_deltat) u.av_max_renew_life;
break;
case AT_EXP:
ent->expiration = (krb5_timestamp) u.av_exp;
break;
case AT_PW_EXP:
ent->pw_expiration = (krb5_timestamp) u.av_pw_exp;
break;
case AT_LAST_SUCCESS:
if (!slave)
ent->last_success = (krb5_timestamp) u.av_last_success;
break;
case AT_LAST_FAILED:
if (!slave)
ent->last_failed = (krb5_timestamp) u.av_last_failed;
break;
case AT_FAIL_AUTH_COUNT:
if (!slave)
ent->fail_auth_count = (krb5_kvno) u.av_fail_auth_count;
break;
case AT_PRINC:
tmpprinc = conv_princ_2db(context, &u.av_princ);
if (tmpprinc == NULL)
return ENOMEM;
if (nprincs)
krb5_free_principal(context, ent->princ);
ent->princ = tmpprinc;
break;
case AT_KEYDATA:
if (nprincs != 0)
prev_n_keys = ent->n_key_data;
else
prev_n_keys = 0;
ent->n_key_data = (krb5_int16)u.av_keydata.av_keydata_len;
if (nprincs == 0)
ent->key_data = NULL;
ent->key_data = (krb5_key_data *)realloc(ent->key_data,
(ent->n_key_data *
sizeof (krb5_key_data)));
/* XXX Memory leak: Old key data in
records eliminated by resizing to
smaller size. */
if (ent->key_data == NULL)
/* XXX Memory leak: old storage. */
return (ENOMEM);
/* BEGIN CSTYLED */
for (j = prev_n_keys; j < ent->n_key_data; j++) {
for (cnt = 0; cnt < 2; cnt++) {
ent->key_data[j].key_data_contents[cnt] = NULL;
}
}
for (j = 0; j < ent->n_key_data; j++) {
krb5_key_data *kp = &ent->key_data[j];
kdbe_key_t *kv = &ULOG_ENTRY_KEYVAL(upd, i, j);
kp->key_data_ver = (krb5_int16)kv->k_ver;
kp->key_data_kvno = (krb5_int16)kv->k_kvno;
if (kp->key_data_ver > 2) {
return EINVAL; /* XXX ? */
}
for (cnt = 0; cnt < kp->key_data_ver; cnt++) {
void *newptr;
kp->key_data_type[cnt] = (krb5_int16)kv->k_enctype.k_enctype_val[cnt];
kp->key_data_length[cnt] = (krb5_int16)kv->k_contents.k_contents_val[cnt].utf8str_t_len;
newptr = realloc(kp->key_data_contents[cnt],
kp->key_data_length[cnt]);
if (newptr == NULL)
return ENOMEM;
kp->key_data_contents[cnt] = newptr;
(void) memset(kp->key_data_contents[cnt], 0,
kp->key_data_length[cnt]);
(void) memcpy(kp->key_data_contents[cnt],
kv->k_contents.k_contents_val[cnt].utf8str_t_val,
kp->key_data_length[cnt]);
}
}
break;
case AT_TL_DATA: {
int t;
cnt = u.av_tldata.av_tldata_len;
newtl = calloc(cnt, sizeof (krb5_tl_data));
if (newtl == NULL)
return (ENOMEM);
for (j = 0, t = 0; j < cnt; j++) {
newtl[t].tl_data_type = (krb5_int16)u.av_tldata.av_tldata_val[j].tl_type;
newtl[t].tl_data_length = (krb5_int16)u.av_tldata.av_tldata_val[j].tl_data.tl_data_len;
newtl[t].tl_data_contents = malloc(newtl[t].tl_data_length * sizeof (krb5_octet));
/* Solaris Kerberos */
if (newtl[t].tl_data_contents == NULL) {
for (j--; j >= 0; j--)
free(newtl[j].tl_data_contents);
free(newtl);
return (ENOMEM);
}
(void) memcpy(newtl[t].tl_data_contents, u.av_tldata.av_tldata_val[t].tl_data.tl_data_val, newtl[t].tl_data_length);
newtl[t].tl_data_next = NULL;
if (t > 0)
newtl[t - 1].tl_data_next = &newtl[t];
t++;
}
if ((ret = krb5_dbe_update_tl_data(context, ent, newtl)))
return (ret);
for (j = 0; j < t; j++)
if (newtl[j].tl_data_contents) {
free(newtl[j].tl_data_contents);
newtl[j].tl_data_contents = NULL;
}
if (newtl) {
free(newtl);
newtl = NULL;
}
break;
/* END CSTYLED */
}
case AT_PW_LAST_CHANGE:
if ((ret = krb5_dbe_update_last_pwd_change(context, ent,
u.av_pw_last_change)))
return (ret);
break;
case AT_MOD_PRINC:
tmpprinc = conv_princ_2db(context, &u.av_mod_princ);
if (tmpprinc == NULL)
return ENOMEM;
mod_princ = tmpprinc;
break;
case AT_MOD_TIME:
mod_time = u.av_mod_time;
break;
case AT_LEN:
ent->len = (krb5_int16) u.av_len;
break;
default:
break;
}
#undef u
}
/*
* process mod_princ_data request
*/
if (mod_time && mod_princ) {
ret = krb5_dbe_update_mod_princ_data(context, ent,
mod_time, mod_princ);
krb5_free_principal(context, mod_princ);
mod_princ = NULL;
if (ret)
return (ret);
}
next:
/*
* Bump up to next struct
*/
upd++;
ent++;
}
return (0);
}
/*
* This routine frees up memory associated with the bunched ulog entries.
*/
void
ulog_free_entries(kdb_incr_update_t *updates, int no_of_updates)
{
kdb_incr_update_t *upd;
int i, j, k, cnt;
if (updates == NULL)
return;
upd = updates;
/*
* Loop thru each ulog entry
*/
for (cnt = 0; cnt < no_of_updates; cnt++) {
/*
* ulog entry - kdb_princ_name
*/
free(upd->kdb_princ_name.utf8str_t_val);
/* BEGIN CSTYLED */
/*
* ulog entry - kdb_kdcs_seen_by
*/
if (upd->kdb_kdcs_seen_by.kdb_kdcs_seen_by_val) {
for (i = 0; i < upd->kdb_kdcs_seen_by.kdb_kdcs_seen_by_len; i++)
free(upd->kdb_kdcs_seen_by.kdb_kdcs_seen_by_val[i].utf8str_t_val);
free(upd->kdb_kdcs_seen_by.kdb_kdcs_seen_by_val);
}
/*
* ulog entry - kdb_futures
*/
free(upd->kdb_futures.kdb_futures_val);
/*
* ulog entry - kdb_update
*/
if (upd->kdb_update.kdbe_t_val) {
/*
* Loop thru all the attributes and free up stuff
*/
for (i = 0; i < upd->kdb_update.kdbe_t_len; i++) {
/*
* Free av_key_data
*/
if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_KEYDATA) && ULOG_ENTRY(upd, i).av_keydata.av_keydata_val) {
for (j = 0; j < ULOG_ENTRY(upd, i).av_keydata.av_keydata_len; j++) {
free(ULOG_ENTRY_KEYVAL(upd, i, j).k_enctype.k_enctype_val);
if (ULOG_ENTRY_KEYVAL(upd, i, j).k_contents.k_contents_val) {
for (k = 0; k < ULOG_ENTRY_KEYVAL(upd, i, j).k_ver; k++) {
free(ULOG_ENTRY_KEYVAL(upd, i, j).k_contents.k_contents_val[k].utf8str_t_val);
}
free(ULOG_ENTRY_KEYVAL(upd, i, j).k_contents.k_contents_val);
}
}
free(ULOG_ENTRY(upd, i).av_keydata.av_keydata_val);
}
/*
* Free av_tl_data
*/
if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_TL_DATA) && ULOG_ENTRY(upd, i).av_tldata.av_tldata_val) {
for (j = 0; j < ULOG_ENTRY(upd, i).av_tldata.av_tldata_len; j++) {
free(ULOG_ENTRY(upd, i).av_tldata.av_tldata_val[j].tl_data.tl_data_val);
}
free(ULOG_ENTRY(upd, i).av_tldata.av_tldata_val);
}
/*
* Free av_princ
*/
if (ULOG_ENTRY_TYPE(upd, i).av_type == AT_PRINC) {
free(ULOG_ENTRY(upd, i).av_princ.k_realm.utf8str_t_val);
if (ULOG_ENTRY(upd, i).av_princ.k_components.k_components_val) {
for (j = 0; j < ULOG_ENTRY(upd, i).av_princ.k_components.k_components_len; j++) {
free(ULOG_ENTRY_PRINC(upd, i, j).k_data.utf8str_t_val);
}
free(ULOG_ENTRY(upd, i).av_princ.k_components.k_components_val);
}
}
/*
* Free av_mod_princ
*/
if (ULOG_ENTRY_TYPE(upd, i).av_type == AT_MOD_PRINC) {
free(ULOG_ENTRY(upd, i).av_mod_princ.k_realm.utf8str_t_val);
if (ULOG_ENTRY(upd, i).av_mod_princ.k_components.k_components_val) {
for (j = 0; j < ULOG_ENTRY(upd, i).av_mod_princ.k_components.k_components_len; j++) {
free(ULOG_ENTRY_MOD_PRINC(upd, i, j).k_data.utf8str_t_val);
}
free(ULOG_ENTRY(upd, i).av_mod_princ.k_components.k_components_val);
}
}
/*
* Free av_mod_where
*/
if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_MOD_WHERE) && ULOG_ENTRY(upd, i).av_mod_where.utf8str_t_val)
free(ULOG_ENTRY(upd, i).av_mod_where.utf8str_t_val);
/*
* Free av_pw_policy
*/
if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_PW_POLICY) && ULOG_ENTRY(upd, i).av_pw_policy.utf8str_t_val)
free(ULOG_ENTRY(upd, i).av_pw_policy.utf8str_t_val);
/*
* XXX: Free av_pw_hist
*
* For now, we just free the pointer
* to av_pw_hist_val, since we aren't
* populating this union member in
* the conv api function(s) anyways.
*/
if ((ULOG_ENTRY_TYPE(upd, i).av_type == AT_PW_HIST) && ULOG_ENTRY(upd, i).av_pw_hist.av_pw_hist_val)
free(ULOG_ENTRY(upd, i).av_pw_hist.av_pw_hist_val);
}
/*
* Free up the pointer to kdbe_t_val
*/
free(upd->kdb_update.kdbe_t_val);
}
/* END CSTYLED */
/*
* Bump up to next struct
*/
upd++;
}
/*
* Finally, free up the pointer to the bunched ulog entries
*/
free(updates);
}