#include "k5-int.h"
#include "int-proto.h"
krb5_error_code KRB5_CALLCONV
krb5_decode_authdata_container(krb5_context context,
krb5_authdatatype type,
const krb5_authdata *container,
krb5_authdata ***authdata)
{
krb5_error_code code;
krb5_data data;
*authdata = NULL;
if ((container->ad_type & AD_TYPE_FIELD_TYPE_MASK) != type)
return EINVAL;
data.length = container->length;
data.data = (char *)container->contents;
code = decode_krb5_authdata(&data, authdata);
if (code)
return code;
return 0;
}
struct find_authdata_context {
krb5_authdata **out;
size_t space;
size_t length;
};
static krb5_error_code
grow_find_authdata(krb5_context context, struct find_authdata_context *fctx,
krb5_authdata *elem)
{
krb5_error_code retval = 0;
if (fctx->length == fctx->space) {
krb5_authdata **new;
if (fctx->space >= 256) {
k5_setmsg(context, ERANGE,
"More than 256 authdata matched a query");
return ERANGE;
}
new = realloc(fctx->out,
sizeof (krb5_authdata *)*(2*fctx->space+1));
if (new == NULL)
return ENOMEM;
fctx->out = new;
fctx->space *=2;
}
fctx->out[fctx->length+1] = NULL;
retval = krb5int_copy_authdatum(context, elem,
&fctx->out[fctx->length]);
if (retval == 0)
fctx->length++;
return retval;
}
static krb5_error_code
find_authdata_1(krb5_context context, krb5_authdata *const *in_authdat,
krb5_authdatatype ad_type, struct find_authdata_context *fctx,
int from_ap_req)
{
size_t i = 0;
krb5_error_code retval = 0;
for (i = 0; in_authdat[i] && retval == 0; i++) {
krb5_authdata *ad = in_authdat[i];
krb5_authdata **decoded_container;
switch (ad->ad_type) {
case KRB5_AUTHDATA_IF_RELEVANT:
if (retval == 0)
retval = krb5_decode_authdata_container(context,
ad->ad_type,
ad,
&decoded_container);
if (retval == 0) {
retval = find_authdata_1(context,
decoded_container,
ad_type,
fctx,
from_ap_req);
krb5_free_authdata(context, decoded_container);
}
break;
case KRB5_AUTHDATA_SIGNTICKET:
case KRB5_AUTHDATA_KDC_ISSUED:
case KRB5_AUTHDATA_WIN2K_PAC:
case KRB5_AUTHDATA_CAMMAC:
case KRB5_AUTHDATA_AUTH_INDICATOR:
if (from_ap_req)
continue;
default:
if (ad->ad_type == ad_type && retval == 0)
retval = grow_find_authdata(context, fctx, ad);
break;
}
}
return retval;
}
krb5_error_code KRB5_CALLCONV
krb5_find_authdata(krb5_context context,
krb5_authdata *const *ticket_authdata,
krb5_authdata *const *ap_req_authdata,
krb5_authdatatype ad_type, krb5_authdata ***results)
{
krb5_error_code retval = 0;
struct find_authdata_context fctx;
fctx.length = 0;
fctx.space = 2;
fctx.out = calloc(fctx.space+1, sizeof (krb5_authdata *));
*results = NULL;
if (fctx.out == NULL)
return ENOMEM;
if (ticket_authdata)
retval = find_authdata_1( context, ticket_authdata, ad_type, &fctx, 0);
if ((retval==0) && ap_req_authdata)
retval = find_authdata_1( context, ap_req_authdata, ad_type, &fctx, 1);
if ((retval== 0) && fctx.length)
*results = fctx.out;
else krb5_free_authdata(context, fctx.out);
return retval;
}
krb5_error_code KRB5_CALLCONV
krb5_verify_authdata_kdc_issued(krb5_context context,
const krb5_keyblock *key,
const krb5_authdata *ad_kdcissued,
krb5_principal *issuer,
krb5_authdata ***authdata)
{
krb5_error_code code;
krb5_ad_kdcissued *ad_kdci;
krb5_data data, *data2;
krb5_boolean valid = FALSE;
if ((ad_kdcissued->ad_type & AD_TYPE_FIELD_TYPE_MASK) !=
KRB5_AUTHDATA_KDC_ISSUED)
return EINVAL;
if (issuer != NULL)
*issuer = NULL;
if (authdata != NULL)
*authdata = NULL;
data.length = ad_kdcissued->length;
data.data = (char *)ad_kdcissued->contents;
code = decode_krb5_ad_kdcissued(&data, &ad_kdci);
if (code != 0)
return code;
if (!krb5_c_is_keyed_cksum(ad_kdci->ad_checksum.checksum_type)) {
krb5_free_ad_kdcissued(context, ad_kdci);
return KRB5KRB_AP_ERR_INAPP_CKSUM;
}
code = encode_krb5_authdata(ad_kdci->elements, &data2);
if (code != 0) {
krb5_free_ad_kdcissued(context, ad_kdci);
return code;
}
code = krb5_c_verify_checksum(context, key,
KRB5_KEYUSAGE_AD_KDCISSUED_CKSUM,
data2, &ad_kdci->ad_checksum, &valid);
if (code != 0) {
krb5_free_ad_kdcissued(context, ad_kdci);
krb5_free_data(context, data2);
return code;
}
krb5_free_data(context, data2);
if (valid == FALSE) {
krb5_free_ad_kdcissued(context, ad_kdci);
return KRB5KRB_AP_ERR_BAD_INTEGRITY;
}
if (issuer != NULL) {
*issuer = ad_kdci->i_principal;
ad_kdci->i_principal = NULL;
}
if (authdata != NULL) {
*authdata = ad_kdci->elements;
ad_kdci->elements = NULL;
}
krb5_free_ad_kdcissued(context, ad_kdci);
return 0;
}
krb5_error_code
k5_authind_decode(const krb5_authdata *ad, krb5_data ***indicators)
{
krb5_error_code ret = 0;
krb5_data der_ad, **strdata = NULL, **ai_list = *indicators;
size_t count, scount;
if (ad == NULL || ad->ad_type != KRB5_AUTHDATA_AUTH_INDICATOR)
goto cleanup;
for (count = 0; ai_list != NULL && ai_list[count] != NULL; count++);
der_ad = make_data(ad->contents, ad->length);
ret = decode_utf8_strings(&der_ad, &strdata);
if (ret)
return ret;
for (scount = 0; strdata[scount] != NULL; scount++);
ai_list = realloc(ai_list, (count + scount + 1) * sizeof(*ai_list));
if (ai_list == NULL) {
ret = ENOMEM;
goto cleanup;
}
*indicators = ai_list;
memcpy(ai_list + count, strdata, scount * sizeof(*strdata));
ai_list[count + scount] = NULL;
free(strdata);
strdata = NULL;
cleanup:
k5_free_data_ptr_list(strdata);
return ret;
}