#include "k5-int.h"
#include "authdata.h"
#include "auth_con.h"
#include "int-proto.h"
struct authind_context {
krb5_data **indicators;
};
static krb5_error_code
authind_init(krb5_context kcontext, void **plugin_context)
{
*plugin_context = NULL;
return 0;
}
static void
authind_flags(krb5_context kcontext, void *plugin_context,
krb5_authdatatype ad_type, krb5_flags *flags)
{
*flags = AD_CAMMAC_PROTECTED;
}
static krb5_error_code
authind_request_init(krb5_context kcontext, krb5_authdata_context context,
void *plugin_context, void **request_context)
{
krb5_error_code ret = 0;
struct authind_context *aictx;
*request_context = NULL;
aictx = k5alloc(sizeof(*aictx), &ret);
if (aictx == NULL)
return ret;
aictx->indicators = NULL;
*request_context = aictx;
return ret;
}
static krb5_error_code
authind_import_authdata(krb5_context kcontext, krb5_authdata_context context,
void *plugin_context, void *request_context,
krb5_authdata **authdata, krb5_boolean kdc_issued,
krb5_const_principal kdc_issuer)
{
struct authind_context *aictx = request_context;
krb5_error_code ret = 0;
krb5_data **indps = NULL;
size_t i;
for (i = 0; authdata != NULL && authdata[i] != NULL; i++) {
ret = k5_authind_decode(authdata[i], &indps);
if (ret)
goto cleanup;
}
if (indps != NULL && *indps != NULL) {
aictx->indicators = indps;
indps = NULL;
}
cleanup:
k5_free_data_ptr_list(indps);
return ret;
}
static void
authind_request_fini(krb5_context kcontext, krb5_authdata_context context,
void *plugin_context, void *request_context)
{
struct authind_context *aictx = request_context;
if (aictx != NULL) {
k5_free_data_ptr_list(aictx->indicators);
free(aictx);
}
}
static krb5_data authind_attr = {
KV5M_DATA,
sizeof("auth-indicators") - 1,
"auth-indicators"
};
static krb5_error_code
authind_get_attribute_types(krb5_context kcontext,
krb5_authdata_context context,
void *plugin_context, void *request_context,
krb5_data **out_attrs)
{
struct authind_context *aictx = request_context;
krb5_error_code ret;
krb5_data *attrs;
*out_attrs = NULL;
if (aictx->indicators == NULL || *aictx->indicators == NULL)
return ENOENT;
attrs = k5calloc(2, sizeof(*attrs), &ret);
if (attrs == NULL)
return ENOMEM;
ret = krb5int_copy_data_contents(kcontext, &authind_attr, &attrs[0]);
if (ret)
goto cleanup;
attrs[1].data = NULL;
attrs[1].length = 0;
*out_attrs = attrs;
attrs = NULL;
cleanup:
krb5int_free_data_list(kcontext, attrs);
return ret;
}
static krb5_error_code
authind_get_attribute(krb5_context kcontext, krb5_authdata_context context,
void *plugin_context, void *request_context,
const krb5_data *attribute, krb5_boolean *authenticated,
krb5_boolean *complete, krb5_data *value,
krb5_data *display_value, int *more)
{
struct authind_context *aictx = request_context;
krb5_error_code ret;
int ind;
if (!data_eq(*attribute, authind_attr))
return ENOENT;
ind = (*more < 0) ? 0 : *more;
if (aictx->indicators == NULL || aictx->indicators[ind] == NULL)
return ENOENT;
ret = krb5int_copy_data_contents(kcontext, aictx->indicators[ind], value);
if (ret)
return ret;
*more = (aictx->indicators[ind + 1] == NULL) ? 0 : ind + 1;
*authenticated = TRUE;
*complete = TRUE;
return ret;
}
static krb5_error_code
authind_set_attribute(krb5_context kcontext, krb5_authdata_context context,
void *plugin_context, void *request_context,
krb5_boolean complete, const krb5_data *attribute,
const krb5_data *value)
{
if (!data_eq(*attribute, authind_attr))
return ENOENT;
return EPERM;
}
static krb5_error_code
authind_size(krb5_context kcontext, krb5_authdata_context context,
void *plugin_context, void *request_context, size_t *sizep)
{
struct authind_context *aictx = request_context;
size_t i;
*sizep += sizeof(int32_t);
for (i = 0; aictx->indicators != NULL && aictx->indicators[i] != NULL; i++)
*sizep += sizeof(int32_t) + aictx->indicators[i]->length;
return 0;
}
static krb5_error_code
authind_externalize(krb5_context kcontext, krb5_authdata_context context,
void *plugin_context, void *request_context,
uint8_t **buffer, size_t *lenremain)
{
struct authind_context *aictx = request_context;
krb5_error_code ret = 0;
uint8_t *bp = *buffer;
size_t remain = *lenremain;
size_t i, count;
if (aictx->indicators == NULL)
return krb5_ser_pack_int32(0, buffer, lenremain);
for (count = 0; aictx->indicators[count] != NULL; count++);
ret = krb5_ser_pack_int32(count, &bp, &remain);
if (ret)
return ret;
for (i = 0; aictx->indicators[i] != NULL; i++) {
ret = krb5_ser_pack_int32(aictx->indicators[i]->length, &bp, &remain);
if (ret)
return ret;
ret = krb5_ser_pack_bytes((uint8_t *)aictx->indicators[i]->data,
aictx->indicators[i]->length, &bp, &remain);
if (ret)
return ret;
}
*buffer = bp;
*lenremain = remain;
return ret;
}
static krb5_error_code
authind_internalize(krb5_context kcontext, krb5_authdata_context context,
void *plugin_context, void *request_context,
uint8_t **buffer, size_t *lenremain)
{
struct authind_context *aictx = request_context;
krb5_error_code ret;
int32_t count, len, i;
uint8_t *bp = *buffer;
size_t remain = *lenremain;
krb5_data **inds = NULL;
ret = krb5_ser_unpack_int32(&count, &bp, &remain);
if (ret)
return ret;
if (count < 0 || (size_t)count > remain)
return ERANGE;
if (count > 0) {
inds = k5calloc(count + 1, sizeof(*inds), &ret);
if (inds == NULL)
return errno;
}
for (i = 0; i < count; i++) {
ret = krb5_ser_unpack_int32(&len, &bp, &remain);
if (ret)
goto cleanup;
if (len < 0 || (size_t)len > remain) {
ret = ERANGE;
goto cleanup;
}
inds[i] = k5alloc(sizeof(*inds[i]), &ret);
if (inds[i] == NULL)
goto cleanup;
ret = alloc_data(inds[i], len);
if (ret)
goto cleanup;
ret = krb5_ser_unpack_bytes((uint8_t *)inds[i]->data, len, &bp,
&remain);
if (ret)
goto cleanup;
}
k5_free_data_ptr_list(aictx->indicators);
aictx->indicators = inds;
inds = NULL;
*buffer = bp;
*lenremain = remain;
cleanup:
k5_free_data_ptr_list(inds);
return ret;
}
static krb5_authdatatype authind_ad_types[] = {
KRB5_AUTHDATA_AUTH_INDICATOR, 0
};
krb5plugin_authdata_client_ftable_v0 k5_authind_ad_client_ftable = {
"authentication-indicators",
authind_ad_types,
authind_init,
NULL,
authind_flags,
authind_request_init,
authind_request_fini,
authind_get_attribute_types,
authind_get_attribute,
authind_set_attribute,
NULL,
NULL,
authind_import_authdata,
NULL,
NULL,
NULL,
authind_size,
authind_externalize,
authind_internalize,
NULL
};