X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=mech_eap%2Futil_radius.cpp;h=5462acc1f197ea8f030fdcc240c38304fb7e0110;hb=1362e293dfa2caa348b55aed5861efdb483ef813;hp=a6d186bb2101db35bd9627c507f9338cabbbfd0d;hpb=129f62b52a9e5ff093bc2b576bb0b5035b1c4ab9;p=moonshot.git diff --git a/mech_eap/util_radius.cpp b/mech_eap/util_radius.cpp index a6d186b..5462acc 100644 --- a/mech_eap/util_radius.cpp +++ b/mech_eap/util_radius.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, JANET(UK) + * Copyright (c) 2011, JANET(UK) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,90 +30,74 @@ * SUCH DAMAGE. */ +/* + * RADIUS attribute provider implementation. + */ + #include "gssapiP_eap.h" -VALUE_PAIR * -gss_eap_radius_attr_provider::copyAvps(const VALUE_PAIR *src) -{ - const VALUE_PAIR *vp; - VALUE_PAIR *dst = NULL, **pDst = &dst; +/* stuff that should be provided by libradsec/libfreeradius-radius */ +#define VENDORATTR(vendor, attr) (((vendor) << 16) | (attr)) - for (vp = src; vp != NULL; vp = vp->next) { - VALUE_PAIR *vp2; +#ifndef ATTRID +#define ATTRID(attr) ((attr) & 0xFFFF) +#endif - vp2 = (VALUE_PAIR *)GSSEAP_CALLOC(1, sizeof(*vp2)); - if (vp2 == NULL) { - rc_avpair_free(dst); - return NULL; - } - memcpy(vp2, vp, sizeof(*vp)); - vp2->next = NULL; - *pDst = vp2; - pDst = &vp2->next; - } +static gss_buffer_desc radiusUrnPrefix = { + sizeof("urn:x-radius:") - 1, + (void *)"urn:x-radius:" +}; - return dst; -} +static VALUE_PAIR *copyAvps(const VALUE_PAIR *src); gss_eap_radius_attr_provider::gss_eap_radius_attr_provider(void) { - m_rh = NULL; - m_avps = NULL; + m_vps = NULL; m_authenticated = false; } gss_eap_radius_attr_provider::~gss_eap_radius_attr_provider(void) { - if (m_rh != NULL) - rc_config_free(m_rh); - if (m_avps != NULL) - rc_avpair_free(m_avps); -} - -bool -gss_eap_radius_attr_provider::initFromGssCred(const gss_cred_id_t cred) -{ - OM_uint32 minor; - - return !GSS_ERROR(gssEapRadiusAllocHandle(&minor, cred, &m_rh)); + if (m_vps != NULL) + pairfree(&m_vps); } bool -gss_eap_radius_attr_provider::initFromExistingContext(const gss_eap_attr_ctx *manager, +gss_eap_radius_attr_provider::initWithExistingContext(const gss_eap_attr_ctx *manager, const gss_eap_attr_provider *ctx) { const gss_eap_radius_attr_provider *radius; - if (!gss_eap_attr_provider::initFromExistingContext(manager, ctx)) - return false; - - if (!initFromGssCred(GSS_C_NO_CREDENTIAL)) + if (!gss_eap_attr_provider::initWithExistingContext(manager, ctx)) return false; radius = static_cast(ctx); - if (radius->m_avps != NULL) { - m_avps = copyAvps(radius->getAvps()); - } + + if (radius->m_vps != NULL) + m_vps = copyAvps(const_cast(radius->getAvps())); + + m_authenticated = radius->m_authenticated; return true; } bool -gss_eap_radius_attr_provider::initFromGssContext(const gss_eap_attr_ctx *manager, +gss_eap_radius_attr_provider::initWithGssContext(const gss_eap_attr_ctx *manager, const gss_cred_id_t gssCred, const gss_ctx_id_t gssCtx) { - if (!gss_eap_attr_provider::initFromGssContext(manager, gssCred, gssCtx)) - return false; - - if (!initFromGssCred(gssCred)) + if (!gss_eap_attr_provider::initWithGssContext(manager, gssCred, gssCtx)) return false; if (gssCtx != GSS_C_NO_CONTEXT) { - if (gssCtx->acceptorCtx.avps != NULL) { - m_avps = copyAvps(gssCtx->acceptorCtx.avps); - if (m_avps == NULL) + if (gssCtx->acceptorCtx.vps != NULL) { + m_vps = copyAvps(gssCtx->acceptorCtx.vps); + if (m_vps == NULL) return false; + + /* We assume libradsec validated this for us */ + assert(pairfind(m_vps, PW_MESSAGE_AUTHENTICATOR) != NULL); + m_authenticated = true; } } @@ -134,58 +118,111 @@ alreadyAddedAttributeP(std::vector &attrs, VALUE_PAIR *vp) } static bool -isHiddenAttributeP(int attrid, int vendor) +isSecretAttributeP(uint16_t attrid, uint16_t vendor) { - bool ret = false; + bool bSecretAttribute = false; switch (vendor) { - case RADIUS_VENDOR_ID_MICROSOFT: + case VENDORPEC_MS: switch (attrid) { - case RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY: - case RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY: - ret = true; + case PW_MS_MPPE_SEND_KEY: + case PW_MS_MPPE_RECV_KEY: + bSecretAttribute = true; break; default: break; } - case RADIUS_VENDOR_ID_GSS_EAP: - ret = true; + default: + break; + } + + return bSecretAttribute; +} + +static bool +isSecretAttributeP(uint32_t attribute) +{ + return isSecretAttributeP(ATTRID(attribute), VENDOR(attribute)); +} + +static bool +isInternalAttributeP(uint16_t attrid, uint16_t vendor) +{ + bool bInternalAttribute = false; + + /* should have been filtered */ + assert(!isSecretAttributeP(attrid, vendor)); + + switch (vendor) { + case VENDORPEC_UKERNA: + bInternalAttribute = true; break; default: break; } - return ret; + return bInternalAttribute; +} + +static bool +isInternalAttributeP(uint32_t attribute) +{ + return isInternalAttributeP(ATTRID(attribute), VENDOR(attribute)); +} + +/* + * Copy AVP list, same as paircopy except it filters out attributes + * containing keys. + */ +static VALUE_PAIR * +copyAvps(const VALUE_PAIR *src) +{ + const VALUE_PAIR *vp; + VALUE_PAIR *dst = NULL, **pDst = &dst; + + for (vp = src; vp != NULL; vp = vp->next) { + VALUE_PAIR *vpcopy; + + if (isSecretAttributeP(vp->attribute)) + continue; + + vpcopy = paircopyvp(vp); + if (vpcopy == NULL) { + pairfree(&dst); + throw std::bad_alloc(); + } + *pDst = vpcopy; + pDst = &vpcopy->next; + } + + return dst; } bool -gss_eap_radius_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute, void *data) const +gss_eap_radius_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute, + void *data) const { VALUE_PAIR *vp; std::vector seen; - for (vp = m_avps; vp != NULL; vp = vp->next) { + for (vp = m_vps; vp != NULL; vp = vp->next) { gss_buffer_desc attribute; -#ifndef RADIUS_STRING_ATTRS char attrid[64]; -#endif - if (isHiddenAttributeP(ATTRID(vp->attribute), VENDOR(vp->attribute))) + + /* Don't advertise attributes that are internal to the GSS-EAP mechanism */ + if (isInternalAttributeP(vp->attribute)) continue; if (alreadyAddedAttributeP(seen, vp)) continue; -#ifdef RADIUS_STRING_ATTRS - attribute.value = (void *)vp->name; - attribute.length = strlen(vp->name); -#else - snprintf(attrid, sizeof(attrid), "%d", vp->attribute); + snprintf(attrid, sizeof(attrid), "%s%d", + (char *)radiusUrnPrefix.value, vp->attribute); attribute.value = attrid; attribute.length = strlen(attrid); -#endif /* RADIUS_STRING_ATTRS */ - if (!addAttribute(this, &attribute, data)) + if (!addAttribute(m_manager, this, &attribute, data)) return false; seen.push_back(std::string(vp->name)); @@ -194,104 +231,130 @@ gss_eap_radius_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addA return true; } -void -gss_eap_radius_attr_provider::setAttribute(int complete, - const gss_buffer_t attr, - const gss_buffer_t value) -{ -} - -void -gss_eap_radius_attr_provider::deleteAttribute(const gss_buffer_t value) -{ -} - -bool -gss_eap_radius_attr_provider::getAttribute(const gss_buffer_t attr, - int *authenticated, - int *complete, - gss_buffer_t value, - gss_buffer_t display_value, - int *more) const +uint32_t +getAttributeId(const gss_buffer_t attr) { OM_uint32 tmpMinor; gss_buffer_desc strAttr = GSS_C_EMPTY_BUFFER; - DICT_ATTR *d; - int attrid; + DICT_ATTR *da; char *s; + uint32_t attrid = 0; - /* XXX vendor */ + if (attr->length < radiusUrnPrefix.length || + memcmp(attr->value, radiusUrnPrefix.value, radiusUrnPrefix.length) != 0) + return 0; + /* need to duplicate because attr may not be NUL terminated */ duplicateBuffer(*attr, &strAttr); - s = (char *)strAttr.value; + s = (char *)strAttr.value + radiusUrnPrefix.length; - if (isdigit(((char *)strAttr.value)[0])) { + if (isdigit(*s)) { attrid = strtoul(s, NULL, 10); } else { - d = rc_dict_findattr(m_rh, (char *)s); - if (d == NULL) { - gss_release_buffer(&tmpMinor, &strAttr); - return false; - } - attrid = d->value; + da = dict_attrbyname(s); + if (da != NULL) + attrid = da->attr; } gss_release_buffer(&tmpMinor, &strAttr); - return getAttribute(attrid, authenticated, complete, - value, display_value, more); + return attrid; } -static bool -isPrintableAttributeP(VALUE_PAIR *vp) +bool +gss_eap_radius_attr_provider::setAttribute(int complete GSSEAP_UNUSED, + uint32_t attrid, + const gss_buffer_t value) { - size_t i; - int gotChar = 0; - - for (i = 0; i < sizeof(vp->strvalue); i++) { - if (gotChar && vp->strvalue[i] == '\0') - return true; + OM_uint32 major = GSS_S_UNAVAILABLE, minor; - if (!isprint(vp->strvalue[i])) - return false; + if (!isSecretAttributeP(attrid) && + !isInternalAttributeP(attrid)) { + deleteAttribute(attrid); - if (!gotChar) - gotChar++; + major = gssEapRadiusAddAvp(&minor, &m_vps, + ATTRID(attrid), VENDOR(attrid), + value); } + return !GSS_ERROR(major); +} + +bool +gss_eap_radius_attr_provider::setAttribute(int complete, + const gss_buffer_t attr, + const gss_buffer_t value) +{ + uint32_t attrid = getAttributeId(attr); + + if (!attrid) + return false; + + return setAttribute(complete, attrid, value); +} + +bool +gss_eap_radius_attr_provider::deleteAttribute(uint32_t attrid) +{ + if (isSecretAttributeP(attrid) || isInternalAttributeP(attrid) || + pairfind(m_vps, attrid) == NULL) + return false; + + pairdelete(&m_vps, attrid); + return true; } bool -gss_eap_radius_attr_provider::getAttribute(int attrid, - int vendor, +gss_eap_radius_attr_provider::deleteAttribute(const gss_buffer_t attr) +{ + uint32_t attrid = getAttributeId(attr); + + if (!attrid) + return false; + + return deleteAttribute(attrid); +} + +bool +gss_eap_radius_attr_provider::getAttribute(const gss_buffer_t attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) const +{ + uint32_t attrid; + + attrid = getAttributeId(attr); + if (!attrid) + return false; + + return getAttribute(attrid, authenticated, complete, + value, display_value, more); +} + +bool +gss_eap_radius_attr_provider::getAttribute(uint32_t attrid, int *authenticated, int *complete, gss_buffer_t value, gss_buffer_t display_value, int *more) const { - OM_uint32 tmpMinor; VALUE_PAIR *vp; int i = *more, count = 0; - char name[NAME_LENGTH + 1]; - char displayString[AUTH_STRING_LEN + 1]; - gss_buffer_desc valueBuf = GSS_C_EMPTY_BUFFER; - gss_buffer_desc displayBuf = GSS_C_EMPTY_BUFFER; *more = 0; - if (isHiddenAttributeP(attrid, vendor)) - return false; - if (i == -1) i = 0; - for (vp = rc_avpair_get(m_avps, attrid, vendor); + for (vp = pairfind(m_vps, attrid); vp != NULL; - vp = rc_avpair_get(vp->next, attrid, vendor)) { + vp = pairfind(vp->next, attrid)) { if (count++ == i) { - if (rc_avpair_get(vp->next, attrid, vendor) != NULL) + if (pairfind(vp->next, attrid) != NULL) *more = count; break; } @@ -300,27 +363,22 @@ gss_eap_radius_attr_provider::getAttribute(int attrid, if (vp == NULL && *more == 0) return false; - if (vp->type == PW_TYPE_STRING) { - valueBuf.value = (void *)vp->strvalue; - valueBuf.length = vp->lvalue; - } else { - valueBuf.value = (void *)&vp->lvalue; - valueBuf.length = 4; - } + if (value != GSS_C_NO_BUFFER) { + gss_buffer_desc valueBuf; + + valueBuf.value = (void *)vp->vp_octets; + valueBuf.length = vp->length; - if (value != GSS_C_NO_BUFFER) duplicateBuffer(valueBuf, value); + } - if (display_value != GSS_C_NO_BUFFER && - isPrintableAttributeP(vp)) { - if (rc_avpair_tostr(m_rh, vp, name, NAME_LENGTH, - displayString, AUTH_STRING_LEN) != 0) { - gss_release_buffer(&tmpMinor, value); - return false; - } + if (display_value != GSS_C_NO_BUFFER) { + char displayString[MAX_STRING_LEN]; + gss_buffer_desc displayBuf; + displayBuf.length = vp_prints_value(displayString, + sizeof(displayString), vp, 0); displayBuf.value = (void *)displayString; - displayBuf.length = strlen(displayString); duplicateBuffer(displayBuf, display_value); } @@ -334,15 +392,15 @@ gss_eap_radius_attr_provider::getAttribute(int attrid, } bool -gss_eap_radius_attr_provider::getFragmentedAttribute(int attribute, - int vendor, +gss_eap_radius_attr_provider::getFragmentedAttribute(uint16_t attribute, + uint16_t vendor, int *authenticated, int *complete, gss_buffer_t value) const { OM_uint32 major, minor; - major = getBufferFromAvps(&minor, m_avps, attribute, vendor, value, TRUE); + major = gssEapRadiusGetAvp(&minor, m_vps, attribute, vendor, value, TRUE); if (authenticated != NULL) *authenticated = m_authenticated; @@ -353,7 +411,8 @@ gss_eap_radius_attr_provider::getFragmentedAttribute(int attribute, } bool -gss_eap_radius_attr_provider::getAttribute(int attrid, +gss_eap_radius_attr_provider::getAttribute(uint16_t attribute, + uint16_t vendor, int *authenticated, int *complete, gss_buffer_t value, @@ -361,34 +420,58 @@ gss_eap_radius_attr_provider::getAttribute(int attrid, int *more) const { - return getAttribute(ATTRID(attrid), VENDOR(attrid), + return getAttribute(VENDORATTR(attribute, vendor), authenticated, complete, value, display_value, more); } gss_any_t gss_eap_radius_attr_provider::mapToAny(int authenticated, - gss_buffer_t type_id) const + gss_buffer_t type_id GSSEAP_UNUSED) const { if (authenticated && !m_authenticated) return (gss_any_t)NULL; - return (gss_any_t)copyAvps(m_avps); + return (gss_any_t)copyAvps(m_vps); } void -gss_eap_radius_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id, +gss_eap_radius_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED, gss_any_t input) const { - rc_avpair_free((VALUE_PAIR *)input); + VALUE_PAIR *vp = (VALUE_PAIR *)input; + pairfree(&vp); } bool gss_eap_radius_attr_provider::init(void) { - gss_eap_attr_ctx::registerProvider(ATTR_TYPE_RADIUS, - "urn:ietf:params:gss-eap:radius-avp", - gss_eap_radius_attr_provider::createAttrContext); + struct rs_context *radContext; + + gss_eap_attr_ctx::registerProvider(ATTR_TYPE_RADIUS, createAttrContext); + +#if 1 + /* + * This hack is necessary in order to force the loading of the global + * dictionary, otherwise accepting reauthentication tokens fails unless + * the acceptor has already accepted a normal authentication token. + */ + if (rs_context_create(&radContext) != 0) + return false; + + if (rs_context_read_config(radContext, RS_CONFIG_FILE) != 0) { + rs_context_destroy(radContext); + return false; + } + + if (rs_context_init_freeradius_dict(radContext, NULL)) { + rs_context_destroy(radContext); + return false; + } + + rs_context_destroy(radContext); +#endif + return true; } @@ -405,42 +488,87 @@ gss_eap_radius_attr_provider::createAttrContext(void) } OM_uint32 -addAvpFromBuffer(OM_uint32 *minor, - rc_handle *rh, - VALUE_PAIR **vp, - int type, - int vendor, - gss_buffer_t buffer) -{ - if (rc_avpair_add(rh, vp, type, - buffer->value, buffer->length, vendor) == NULL) { - return GSS_S_FAILURE; +gssEapRadiusAddAvp(OM_uint32 *minor, + VALUE_PAIR **vps, + uint16_t attribute, + uint16_t vendor, + const gss_buffer_t buffer) +{ + uint32_t attrid = VENDORATTR(vendor, attribute); + unsigned char *p = (unsigned char *)buffer->value; + size_t remain = buffer->length; + + do { + VALUE_PAIR *vp; + size_t n = remain; + + /* + * There's an extra byte of padding; RADIUS AVPs can only + * be 253 octets. + */ + if (n >= MAX_STRING_LEN) + n = MAX_STRING_LEN - 1; + + vp = paircreate(attrid, PW_TYPE_OCTETS); + if (vp == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + memcpy(vp->vp_octets, p, n); + vp->length = n; + + pairadd(vps, vp); + + p += n; + remain -= n; + } while (remain != 0); + + return GSS_S_COMPLETE; +} + +OM_uint32 +gssEapRadiusGetRawAvp(OM_uint32 *minor, + VALUE_PAIR *vps, + uint16_t attribute, + uint16_t vendor, + VALUE_PAIR **vp) +{ + uint32_t attr = VENDORATTR(vendor, attribute); + + *vp = pairfind(vps, attr); + if (*vp == NULL) { + *minor = GSSEAP_NO_SUCH_ATTR; + return GSS_S_UNAVAILABLE; } return GSS_S_COMPLETE; } OM_uint32 -getBufferFromAvps(OM_uint32 *minor, - VALUE_PAIR *vps, - int type, - int vendor, - gss_buffer_t buffer, - int concat) +gssEapRadiusGetAvp(OM_uint32 *minor, + VALUE_PAIR *vps, + uint16_t attribute, + uint16_t vendor, + gss_buffer_t buffer, + int concat) { VALUE_PAIR *vp; unsigned char *p; + uint32_t attr = VENDORATTR(vendor, attribute); buffer->length = 0; buffer->value = NULL; - vp = rc_avpair_get(vps, type, vendor); - if (vp == NULL) + vp = pairfind(vps, attr); + if (vp == NULL) { + *minor = GSSEAP_NO_SUCH_ATTR; return GSS_S_UNAVAILABLE; + } do { - buffer->length += vp->lvalue; - } while (concat && (vp = rc_avpair_get(vp->next, type, vendor)) != NULL); + buffer->length += vp->length; + } while (concat && (vp = pairfind(vp->next, attr)) != NULL); buffer->value = GSSEAP_MALLOC(buffer->length); if (buffer->value == NULL) { @@ -450,11 +578,11 @@ getBufferFromAvps(OM_uint32 *minor, p = (unsigned char *)buffer->value; - for (vp = rc_avpair_get(vps, type, vendor); + for (vp = pairfind(vps, attr); concat && vp != NULL; - vp = rc_avpair_get(vp->next, type, vendor)) { - memcpy(p, vp->strvalue, vp->lvalue); - p += vp->lvalue; + vp = pairfind(vp->next, attr)) { + memcpy(p, vp->vp_octets, vp->length); + p += vp->length; } *minor = 0; @@ -462,201 +590,236 @@ getBufferFromAvps(OM_uint32 *minor, } OM_uint32 +gssEapRadiusFreeAvps(OM_uint32 *minor, + VALUE_PAIR **vps) +{ + pairfree(vps); + *minor = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 gssEapRadiusAttrProviderInit(OM_uint32 *minor) { - return gss_eap_radius_attr_provider::init() - ? GSS_S_COMPLETE : GSS_S_FAILURE; + if (!gss_eap_radius_attr_provider::init()) { + *minor = GSSEAP_RADSEC_INIT_FAILURE; + return GSS_S_FAILURE; + } + + return GSS_S_COMPLETE; } OM_uint32 gssEapRadiusAttrProviderFinalize(OM_uint32 *minor) { gss_eap_radius_attr_provider::finalize(); + + *minor = 0; return GSS_S_COMPLETE; } -OM_uint32 -gssEapRadiusAllocHandle(OM_uint32 *minor, - const gss_cred_id_t cred, - rc_handle **pHandle) +static JSONObject +avpToJson(const VALUE_PAIR *vp) { - rc_handle *rh; - const char *config = RC_CONFIG_FILE; + JSONObject obj; - *pHandle = NULL; + assert(vp->length <= MAX_STRING_LEN); - if (cred != GSS_C_NO_CREDENTIAL && cred->radiusConfigFile != NULL) - config = cred->radiusConfigFile; + switch (vp->type) { + case PW_TYPE_INTEGER: + case PW_TYPE_IPADDR: + case PW_TYPE_DATE: + obj.set("value", vp->lvalue); + break; + case PW_TYPE_STRING: + obj.set("value", vp->vp_strvalue); + break; + default: { + char *b64; - rh = rc_read_config((char *)config); - if (rh == NULL) { - *minor = errno; - rc_config_free(rh); - return GSS_S_FAILURE; - } + if (base64Encode(vp->vp_octets, vp->length, &b64) < 0) + throw std::bad_alloc(); - if (rc_read_dictionary(rh, rc_conf_str(rh, (char *)"dictionary")) != 0) { - *minor = errno; - return GSS_S_FAILURE; + obj.set("value", b64); + GSSEAP_FREE(b64); + break; + } } - *pHandle = rh; - return GSS_S_COMPLETE; -} + obj.set("type", vp->attribute); -/* - * This is a super-inefficient coding but the API is going to change - * as are the data structures, so not putting a lot of work in now. - */ -static size_t -avpSize(const VALUE_PAIR *vp) -{ - return NAME_LENGTH + 1 + 12 + AUTH_STRING_LEN + 1; + return obj; } static bool -avpExport(const VALUE_PAIR *vp, - unsigned char **pBuffer, - size_t *pRemain) +jsonToAvp(VALUE_PAIR **pVp, JSONObject &obj) { - unsigned char *p = *pBuffer; - size_t remain = *pRemain; - - assert(remain >= avpSize(vp)); - - memcpy(p, vp->name, NAME_LENGTH + 1); - p += NAME_LENGTH + 1; - remain -= NAME_LENGTH + 1; + VALUE_PAIR *vp = NULL; + DICT_ATTR *da; + uint32_t attrid; - store_uint32_be(vp->attribute, &p[0]); - store_uint32_be(vp->type, &p[4]); - store_uint32_be(vp->lvalue, &p[8]); + JSONObject type = obj["type"]; + JSONObject value = obj["value"]; - p += 12; - remain -= 12; + if (!type.isInteger()) + goto fail; - memcpy(p, vp->strvalue, AUTH_STRING_LEN + 1); - p += AUTH_STRING_LEN + 1; - remain -= AUTH_STRING_LEN + 1; - - *pBuffer = p; - *pRemain = remain; + attrid = type.integer(); + da = dict_attrbyvalue(attrid); + if (da != NULL) { + vp = pairalloc(da); + } else { + int type = base64Valid(value.string()) ? + PW_TYPE_OCTETS : PW_TYPE_STRING; + vp = paircreate(attrid, type); + } + if (vp == NULL) + throw std::bad_alloc(); - return true; + switch (vp->type) { + case PW_TYPE_INTEGER: + case PW_TYPE_IPADDR: + case PW_TYPE_DATE: + if (!value.isInteger()) + goto fail; -} + vp->length = 4; + vp->lvalue = value.integer(); + break; + case PW_TYPE_STRING: { + if (!value.isString()) + goto fail; -static bool -avpImport(VALUE_PAIR **pVp, - unsigned char **pBuffer, - size_t *pRemain) -{ - unsigned char *p = *pBuffer; - size_t remain = *pRemain; - VALUE_PAIR *vp; + const char *str = value.string(); + size_t len = strlen(str); - if (remain < avpSize(NULL)) { - return false; - } + if (len >= MAX_STRING_LEN) + goto fail; - vp = (VALUE_PAIR *)GSSEAP_CALLOC(1, sizeof(*vp)); - if (vp == NULL) { - throw new std::bad_alloc; - return false; + vp->length = len; + memcpy(vp->vp_strvalue, str, len + 1); + break; } - vp->next = NULL; + case PW_TYPE_OCTETS: + default: { + if (!value.isString()) + goto fail; - memcpy(vp->name, p, NAME_LENGTH + 1); - p += NAME_LENGTH + 1; - remain -= NAME_LENGTH + 1; + const char *str = value.string(); + ssize_t len = strlen(str); - vp->attribute = load_uint32_be(&p[0]); - vp->type = load_uint32_be(&p[4]); - vp->lvalue = load_uint32_be(&p[8]); + /* this optimization requires base64Decode only understand packed encoding */ + if (len >= BASE64_EXPAND(MAX_STRING_LEN)) + goto fail; - p += 12; - remain -= 12; + len = base64Decode(str, vp->vp_octets); + if (len < 0) + goto fail; - memcpy(vp->strvalue, p, AUTH_STRING_LEN + 1); - p += AUTH_STRING_LEN + 1; - remain -= AUTH_STRING_LEN + 1; + vp->length = len; + break; + } + } *pVp = vp; - *pBuffer = p; - *pRemain = remain; return true; + +fail: + if (vp != NULL) + pairbasicfree(vp); + *pVp = NULL; + return false; +} + +const char * +gss_eap_radius_attr_provider::name(void) const +{ + return "radius"; } bool -gss_eap_radius_attr_provider::initFromBuffer(const gss_eap_attr_ctx *ctx, - const gss_buffer_t buffer) +gss_eap_radius_attr_provider::initWithJsonObject(const gss_eap_attr_ctx *ctx, + JSONObject &obj) { - unsigned char *p = (unsigned char *)buffer->value; - size_t remain = buffer->length; - OM_uint32 count; - VALUE_PAIR **pNext = &m_avps; + VALUE_PAIR **pNext = &m_vps; - if (!gss_eap_attr_provider::initFromBuffer(ctx, buffer)) + if (!gss_eap_attr_provider::initWithJsonObject(ctx, obj)) return false; - if (!initFromGssCred(GSS_C_NO_CREDENTIAL)) - return false; + JSONObject attrs = obj["attributes"]; + size_t nelems = attrs.size(); - if (remain < 4) - return false; + for (size_t i = 0; i < nelems; i++) { + JSONObject attr = attrs[i]; + VALUE_PAIR *vp; - count = load_uint32_be(p); - p += 4; - remain -= 4; + if (!jsonToAvp(&vp, attr)) + return false; - do { - VALUE_PAIR *attr; + *pNext = vp; + pNext = &vp->next; + } - if (!avpImport(&attr, &p, &remain)) - return false; + m_authenticated = obj["authenticated"].integer(); - *pNext = attr; - pNext = &attr->next; + return true; +} - count--; - } while (remain != 0); +const char * +gss_eap_radius_attr_provider::prefix(void) const +{ + return "urn:ietf:params:gss-eap:radius-avp"; +} - if (count != 0) - return false; +JSONObject +gss_eap_radius_attr_provider::jsonRepresentation(void) const +{ + JSONObject obj, attrs = JSONObject::array(); - return true; + for (VALUE_PAIR *vp = m_vps; vp != NULL; vp = vp->next) { + JSONObject attr = avpToJson(vp); + attrs.append(attr); + } + + obj.set("attributes", attrs); + + obj.set("authenticated", m_authenticated); + + return obj; } -void -gss_eap_radius_attr_provider::exportToBuffer(gss_buffer_t buffer) const +time_t +gss_eap_radius_attr_provider::getExpiryTime(void) const { - OM_uint32 count = 0; VALUE_PAIR *vp; - unsigned char *p; - size_t remain = 4; - for (vp = m_avps; vp != NULL; vp = vp->next) { - remain += avpSize(vp); - count++; - } + vp = pairfind(m_vps, PW_SESSION_TIMEOUT); + if (vp == NULL || vp->lvalue == 0) + return 0; - buffer->value = GSSEAP_MALLOC(remain); - if (buffer->value == NULL) { - throw new std::bad_alloc; - return; - } - buffer->length = remain; + return time(NULL) + vp->lvalue; +} - p = (unsigned char *)buffer->value; +OM_uint32 +gssEapRadiusMapError(OM_uint32 *minor, + struct rs_error *err) +{ + int code; - store_uint32_be(count, p); - p += 4; - remain -= 4; + assert(err != NULL); - for (vp = m_avps; vp != NULL; vp = vp->next) { - avpExport(vp, &p, &remain); + code = rs_err_code(err, 0); + + if (code == RSE_OK) { + *minor = 0; + return GSS_S_COMPLETE; } - assert(remain == 0); + *minor = ERROR_TABLE_BASE_rse + code; + + gssEapSaveStatusInfo(*minor, "%s", rs_err_msg(err)); + rs_err_free(err); + + return GSS_S_FAILURE; }