From 4866125c4be79ec72fc388eabba01505786850b4 Mon Sep 17 00:00:00 2001 From: Luke Howard Date: Fri, 8 Oct 2010 15:59:17 +0200 Subject: [PATCH] initial libradsec port --- Makefile.am | 2 +- accept_sec_context.c | 145 +++++++++-------- acinclude.m4 | 4 +- export_sec_context.c | 13 +- gssapiP_eap.h | 26 ++- inquire_attrs_for_mech.c | 2 +- util_context.c | 11 +- util_radius.cpp | 405 +++++++++++++++++++++++++++-------------------- util_radius.h | 78 +++++---- util_saml.cpp | 4 +- 10 files changed, 390 insertions(+), 300 deletions(-) diff --git a/Makefile.am b/Makefile.am index 2370ef4..498390b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,7 +6,7 @@ gssinclude_HEADERS = gssapi_eap.h gssdir = $(libdir)/gss gss_LTLIBRARIES = mech_eap.la -mech_eap_la_CPPFLAGS = -DBUILD_GSSEAP_LIB -DSYSCONFDIR=\"${sysconfdir}\" +mech_eap_la_CPPFLAGS = -DBUILD_GSSEAP_LIB -DSYSCONFDIR=\"${sysconfdir}\" -DDATAROOTDIR=\"${datarootdir}\" mech_eap_la_CFLAGS = -g -Wall -fno-strict-aliasing \ @EAP_CFLAGS@ @RADSEC_CFLAGS@ @KRB5_CFLAGS@ @TARGET_CFLAGS@ mech_eap_la_CXXFLAGS = -g -Wall \ diff --git a/accept_sec_context.c b/accept_sec_context.c index b977242..83d6c2d 100644 --- a/accept_sec_context.c +++ b/accept_sec_context.c @@ -60,10 +60,10 @@ acceptReadyEap(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred) gssEapReleaseName(&tmpMinor, &ctx->initiatorName); - vp = rc_avpair_get(ctx->acceptorCtx.avps, PW_USER_NAME, 0); + vp = pairfind(ctx->acceptorCtx.avps, PW_USER_NAME); if (vp != NULL) { - nameBuf.length = vp->lvalue; - nameBuf.value = vp->strvalue; + nameBuf.length = vp->length; + nameBuf.value = vp->vp_strvalue; } else { ctx->gssFlags |= GSS_C_ANON_FLAG; } @@ -75,13 +75,12 @@ acceptReadyEap(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred) ctx->initiatorName->attrCtx = gssEapCreateAttrContext(cred, ctx); - vp = rc_avpair_get(ctx->acceptorCtx.avps, - VENDOR_ATTR_MS_MPPE_SEND_KEY, - VENDOR_ID_MICROSOFT); - if (ctx->encryptionType != ENCTYPE_NULL && vp != NULL) { + major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.avps, + PW_MS_MPPE_SEND_KEY, VENDORPEC_MS, &vp); + if (major == GSS_S_COMPLETE && ctx->encryptionType != ENCTYPE_NULL) { major = gssEapDeriveRfc3961Key(minor, - (unsigned char *)vp->strvalue, - vp->lvalue, + vp->vp_octets, + vp->length, ctx->encryptionType, &ctx->rfc3961Key); if (GSS_ERROR(major)) @@ -164,7 +163,7 @@ setAcceptorIdentity(OM_uint32 *minor, gss_buffer_desc nameBuf; krb5_context krbContext = NULL; krb5_principal krbPrinc; - rc_handle *rh = ctx->acceptorCtx.radHandle; + struct rs_handle *rh = ctx->acceptorCtx.radHandle; assert(rh != NULL); @@ -183,20 +182,20 @@ setAcceptorIdentity(OM_uint32 *minor, /* Acceptor-Service-Name */ krbDataToGssBuffer(krb5_princ_component(krbContext, krbPrinc, 0), &nameBuf); - major = addAvpFromBuffer(minor, rh, avps, - VENDOR_ATTR_GSS_ACCEPTOR_SERVICE_NAME, - VENDOR_ID_UKERNA, - &nameBuf); + major = gssEapRadiusAddAvp(minor, rh, avps, + PW_GSS_ACCEPTOR_SERVICE_NAME, + VENDORPEC_UKERNA, + &nameBuf); if (GSS_ERROR(major)) return major; /* Acceptor-Host-Name */ krbDataToGssBuffer(krb5_princ_component(krbContext, krbPrinc, 1), &nameBuf); - major = addAvpFromBuffer(minor, rh, avps, - VENDOR_ATTR_GSS_ACCEPTOR_HOST_NAME, - VENDOR_ID_UKERNA, - &nameBuf); + major = gssEapRadiusAddAvp(minor, rh, avps, + PW_GSS_ACCEPTOR_HOST_NAME, + VENDORPEC_UKERNA, + &nameBuf); if (GSS_ERROR(major)) return major; @@ -216,10 +215,10 @@ setAcceptorIdentity(OM_uint32 *minor, nameBuf.value = ssi; nameBuf.length = strlen(ssi); - major = addAvpFromBuffer(minor, rh, avps, - VENDOR_ATTR_GSS_ACCEPTOR_SERVICE_SPECIFIC, - VENDOR_ID_UKERNA, - &nameBuf); + major = gssEapRadiusAddAvp(minor, rh, avps, + PW_GSS_ACCEPTOR_SERVICE_SPECIFIC, + VENDORPEC_UKERNA, + &nameBuf); if (GSS_ERROR(major)) { krb5_free_unparsed_name(krbContext, ssi); @@ -231,10 +230,10 @@ setAcceptorIdentity(OM_uint32 *minor, krbDataToGssBuffer(krb5_princ_realm(krbContext, krbPrinc), &nameBuf); if (nameBuf.length != 0) { /* Acceptor-Realm-Name */ - major = addAvpFromBuffer(minor, rh, avps, - VENDOR_ATTR_GSS_ACCEPTOR_REALM_NAME, - VENDOR_ID_UKERNA, - &nameBuf); + major = gssEapRadiusAddAvp(minor, rh, avps, + PW_GSS_ACCEPTOR_REALM_NAME, + VENDORPEC_UKERNA, + &nameBuf); if (GSS_ERROR(major)) return major; } @@ -251,90 +250,90 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor, gss_buffer_t outputToken) { OM_uint32 major, tmpMinor; - rc_handle *rh; - int code; - VALUE_PAIR *send = NULL; - VALUE_PAIR *received = NULL; - char msgBuffer[4096]; - struct eap_hdr *pdu; - unsigned char *pos; - gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER; + struct rs_handle *rh; + struct rs_connection *rconn; + struct rs_packet *req = NULL, *resp = NULL; + struct radius_packet *frreq, *frresp; + int sendAcceptorIdentity = 0; if (ctx->acceptorCtx.radHandle == NULL) { /* May be NULL from an imported partial context */ - major = gssEapRadiusAllocHandle(minor, cred, ctx); + major = gssEapRadiusAllocConn(minor, cred, ctx); if (GSS_ERROR(major)) goto cleanup; + + sendAcceptorIdentity = 1; } rh = ctx->acceptorCtx.radHandle; + rconn = ctx->acceptorCtx.radConn; - pdu = (struct eap_hdr *)inputToken->value; - pos = (unsigned char *)(pdu + 1); - - if (inputToken->length > sizeof(*pdu) && - pdu->code == EAP_CODE_RESPONSE && - pos[0] == EAP_TYPE_IDENTITY) { - /* - * XXX TODO do we really need to set User-Name? FreeRADIUS does - * not require it but some other RADIUS servers might. - */ - major = addAvpFromBuffer(minor, rh, &send, PW_USER_NAME, 0, &nameBuf); - if (GSS_ERROR(major)) - goto cleanup; + if (rs_packet_create_acc_request(rconn, &req, NULL, NULL) != 0) { + major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn)); + goto cleanup; + } + frreq = rs_packet_frpkt(req); - major = setAcceptorIdentity(minor, ctx, &send); + if (sendAcceptorIdentity) { + major = setAcceptorIdentity(minor, ctx, &frreq->vps); if (GSS_ERROR(major)) goto cleanup; } - major = addAvpFromBuffer(minor, rh, &send, PW_EAP_MESSAGE, 0, inputToken); + major = gssEapRadiusAddAvp(minor, rh, &frreq->vps, PW_EAP_MESSAGE, 0, inputToken); if (GSS_ERROR(major)) goto cleanup; if (ctx->acceptorCtx.state.length != 0) { - major = addAvpFromBuffer(minor, rh, &send, PW_STATE, 0, - &ctx->acceptorCtx.state); + major = gssEapRadiusAddAvp(minor, rh, &frreq->vps, PW_STATE, 0, + &ctx->acceptorCtx.state); if (GSS_ERROR(major)) goto cleanup; gss_release_buffer(&tmpMinor, &ctx->acceptorCtx.state); } - code = rc_auth(rh, 0, send, &received, msgBuffer); - switch (code) { - case OK_RC: - case CHALLENGE_RC: + if (rs_packet_send(req, NULL) != 0) { + major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn)); + goto cleanup; + } + req = NULL; + + if (rs_conn_receive_packet(rconn, &resp) != 0) { + major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn)); + goto cleanup; + } + + frresp = rs_packet_frpkt(resp); + switch (frresp->code) { + case PW_AUTHENTICATION_ACK: + case PW_ACCESS_CHALLENGE: major = GSS_S_CONTINUE_NEEDED; break; - case TIMEOUT_RC: - major = GSS_S_UNAVAILABLE; - break; - case REJECT_RC: + case PW_AUTHENTICATION_REJECT: major = GSS_S_DEFECTIVE_CREDENTIAL; + goto cleanup; break; default: major = GSS_S_FAILURE; goto cleanup; + break; } - if (GSS_ERROR(major)) - goto cleanup; - - major = getBufferFromAvps(minor, received, PW_EAP_MESSAGE, 0, - outputToken, TRUE); - if ((major == GSS_S_UNAVAILABLE && code != OK_RC) || + major = gssEapRadiusGetAvp(minor, frresp->vps, PW_EAP_MESSAGE, 0, + outputToken, TRUE); + if ((major == GSS_S_UNAVAILABLE && frresp->code != PW_AUTHENTICATION_ACK) || GSS_ERROR(major)) goto cleanup; - if (code == CHALLENGE_RC) { - major = getBufferFromAvps(minor, received, PW_STATE, 0, - &ctx->acceptorCtx.state, TRUE); + if (frresp->code == PW_ACCESS_CHALLENGE) { + major = gssEapRadiusGetAvp(minor, frresp->vps, PW_STATE, 0, + &ctx->acceptorCtx.state, TRUE); if (major != GSS_S_UNAVAILABLE && GSS_ERROR(major)) goto cleanup; } else { - ctx->acceptorCtx.avps = received; - received = NULL; + ctx->acceptorCtx.avps = frresp->vps; + frresp->vps = NULL; major = acceptReadyEap(minor, ctx, cred); if (GSS_ERROR(major)) @@ -346,8 +345,8 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor, major = GSS_S_CONTINUE_NEEDED; cleanup: - if (received != NULL) - rc_avpair_free(received); + rs_packet_destroy(req); + rs_packet_destroy(resp); return major; } diff --git a/acinclude.m4 b/acinclude.m4 index fe9254b..2cff774 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -210,8 +210,8 @@ if test x_$found_radsec != x_yes; then else printf "radsec found in $radsecdir\n"; RADSEC_LIBS="-lradsec"; - RADSEC_LDFLAGS="-L$$radsecdir/lib"; - AC_SUBST(RADSEC_CLFAGS) + RADSEC_LDFLAGS="-L$radsecdir/lib"; + AC_SUBST(RADSEC_CFLAGS) AC_SUBST(RADSEC_LDFLAGS) AC_SUBST(RADSEC_LIBS) fi diff --git a/export_sec_context.c b/export_sec_context.c index 001dd5b..46bf118 100644 --- a/export_sec_context.c +++ b/export_sec_context.c @@ -38,13 +38,14 @@ gssEapExportPartialContext(OM_uint32 *minor, gss_buffer_t token) { OM_uint32 major, tmpMinor; - size_t length, serverLen; + size_t length, serverLen = 0; unsigned char *p; + char serverBuf[MAXHOSTNAMELEN]; - if (ctx->acceptorCtx.radServer != NULL) - serverLen = strlen(ctx->acceptorCtx.radServer); - else - serverLen = 0; + if (ctx->acceptorCtx.radConn != NULL && + rs_conn_get_current_server(ctx->acceptorCtx.radConn, + serverBuf, sizeof(serverBuf)) == 0) + serverLen = strlen(serverBuf); length = 4 + serverLen + 4 + ctx->acceptorCtx.state.length; @@ -61,7 +62,7 @@ gssEapExportPartialContext(OM_uint32 *minor, store_uint32_be(serverLen, p); p += 4; if (serverLen != 0) { - memcpy(p, ctx->acceptorCtx.radServer, serverLen); + memcpy(p, serverBuf, serverLen); p += serverLen; } diff --git a/gssapiP_eap.h b/gssapiP_eap.h index 757649b..74fb522 100644 --- a/gssapiP_eap.h +++ b/gssapiP_eap.h @@ -40,6 +40,7 @@ #include #include #include +#include /* GSS includes */ #include @@ -50,7 +51,7 @@ /* Kerberos includes */ #include -/* EAP includes */ +/* EAP includes (not C++ clean) */ #ifndef __cplusplus #include #include @@ -59,11 +60,25 @@ #include #endif -#include +/* Workaround for FreeRADIUS not being C++ clean */ +#ifdef __cplusplus +extern "C" { +#define operator fr_operator +#endif +#include #include +#include +#ifdef __cplusplus +#undef operator +} +#endif #include "util.h" +#ifdef __cplusplus +extern "C" { +#endif + /* These name flags are informative and not actually used by anything yet */ #define NAME_FLAG_NAI 0x00000001 #define NAME_FLAG_SERVICE 0x00000002 @@ -141,7 +156,8 @@ struct gss_eap_initiator_ctx { }; struct gss_eap_acceptor_ctx { - rc_handle *radHandle; + struct rs_handle *radHandle; + struct rs_connection *radConn; char *radServer; gss_buffer_desc state; VALUE_PAIR *avps; @@ -226,4 +242,8 @@ rfc4121Flags(gss_ctx_id_t ctx, int receiving); void gssEapSaveStatusInfo(OM_uint32 minor, const char *format, ...); +#ifdef __cplusplus +} +#endif + #endif /* _GSSAPIP_EAP_H_ */ diff --git a/inquire_attrs_for_mech.c b/inquire_attrs_for_mech.c index 91d654c..fdd8893 100644 --- a/inquire_attrs_for_mech.c +++ b/inquire_attrs_for_mech.c @@ -58,7 +58,7 @@ gss_inquire_attrs_for_mech(OM_uint32 *minor, if (known_mech_attrs != NULL) *known_mech_attrs = GSS_C_NO_OID_SET; - if (!gssEapIsConcreteMechanismOid(mech_oid)) + if (!gssEapIsConcreteMechanismOid((const gss_OID)mech_oid)) return GSS_S_BAD_MECH; if (mech_attrs != NULL) { diff --git a/util_context.c b/util_context.c index 6b5f9df..be42260 100644 --- a/util_context.c +++ b/util_context.c @@ -87,14 +87,15 @@ releaseAcceptorContext(struct gss_eap_acceptor_ctx *ctx) { OM_uint32 tmpMinor; - if (ctx->avps != NULL) - rc_avpair_free(ctx->avps); + if (ctx->radConn != NULL) + rs_conn_destroy(ctx->radConn); if (ctx->radHandle != NULL) - rc_config_free(ctx->radHandle); - - gss_release_buffer(&tmpMinor, &ctx->state); + rs_context_destroy(ctx->radHandle); if (ctx->radServer != NULL) GSSEAP_FREE(ctx->radServer); + gss_release_buffer(&tmpMinor, &ctx->state); + if (ctx->avps != NULL) + pairfree(&ctx->avps); } OM_uint32 diff --git a/util_radius.cpp b/util_radius.cpp index 0fe19ba..15f1217 100644 --- a/util_radius.cpp +++ b/util_radius.cpp @@ -32,60 +32,70 @@ #include "gssapiP_eap.h" +#define VENDORATTR(vendor, attr) ((vendor) << 16 | (attr)) + +#ifndef ATTRID +#define ATTRID(attr) ((attr) & 0xFFFF) +#endif + static gss_buffer_desc radiusUrnPrefix = { sizeof("urn:x-radius:") - 1, (void *)"urn:x-radius:" }; -static int +static void * +gssEapCalloc(size_t nmemb, size_t size) +{ + return GSSEAP_CALLOC(nmemb, size); +} + +static void * +gssEapMalloc(size_t size) +{ + return GSSEAP_MALLOC(size); +} + +static void +gssEapFree(void *ptr) +{ + GSSEAP_FREE(ptr); +} + +static void * +gssEapRealloc(void *ptr, size_t size) +{ + return GSSEAP_REALLOC(ptr, size); +} + +static struct rs_error * radiusAllocHandle(const char *configFile, - rc_handle **pHandle) + rs_handle **pHandle) { - rc_handle *rh; - int ret; + rs_handle *rh; + struct rs_alloc_scheme ralloc; *pHandle = NULL; if (configFile == NULL || configFile[0] == '\0') - configFile = RC_CONFIG_FILE; - - rh = rc_read_config((char *)configFile); - if (rh == NULL) { - rc_config_free(rh); - return -1; - } + configFile = RS_CONFIG_FILE; - ret = rc_read_dictionary(rh, rc_conf_str(rh, (char *)"dictionary")); - if (ret != 0) { - rc_config_free(rh); - return ret; - } - - *pHandle = rh; - return 0; -} + if (rs_context_create(&rh, RS_DICT_FILE) != 0) + return NULL; -VALUE_PAIR * -gss_eap_radius_attr_provider::copyAvps(const VALUE_PAIR *src) -{ - const VALUE_PAIR *vp; - VALUE_PAIR *dst = NULL, **pDst = &dst; + ralloc.calloc = gssEapCalloc; + ralloc.malloc = gssEapMalloc; + ralloc.free = gssEapFree; + ralloc.realloc = gssEapRealloc; - for (vp = src; vp != NULL; vp = vp->next) { - VALUE_PAIR *vp2; + rs_context_set_alloc_scheme(rh, &ralloc); - 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; + if (rs_context_read_config(rh, configFile) != 0) { + rs_context_destroy(rh); + return rs_err_ctx_pop(rh); } - return dst; + *pHandle = rh; + return NULL; } gss_eap_radius_attr_provider::gss_eap_radius_attr_provider(void) @@ -98,9 +108,9 @@ gss_eap_radius_attr_provider::gss_eap_radius_attr_provider(void) gss_eap_radius_attr_provider::~gss_eap_radius_attr_provider(void) { if (m_rh != NULL) - rc_config_free(m_rh); + rs_context_destroy(m_rh); if (m_avps != NULL) - rc_avpair_free(m_avps); + pairfree(&m_avps); } bool @@ -108,7 +118,17 @@ gss_eap_radius_attr_provider::allocRadHandle(const std::string &configFile) { m_configFile.assign(configFile); - return (radiusAllocHandle(m_configFile.c_str(), &m_rh) == 0); + /* + * Currently none of the FreeRADIUS functions we use here actually take + * a handle, so we may as well leave it as NULL. + */ +#if 0 + radiusAllocHandle(m_configFile.c_str(), &m_rh); + + return (m_rh != NULL); +#else + return true; +#endif } bool @@ -126,7 +146,7 @@ gss_eap_radius_attr_provider::initFromExistingContext(const gss_eap_attr_ctx *ma return false; if (radius->m_avps != NULL) - m_avps = copyAvps(radius->getAvps()); + m_avps = paircopy(const_cast(radius->getAvps())); return true; } @@ -136,7 +156,7 @@ gss_eap_radius_attr_provider::initFromGssContext(const gss_eap_attr_ctx *manager const gss_cred_id_t gssCred, const gss_ctx_id_t gssCtx) { - std::string configFile(RC_CONFIG_FILE); + std::string configFile(RS_CONFIG_FILE); if (!gss_eap_attr_provider::initFromGssContext(manager, gssCred, gssCtx)) return false; @@ -149,7 +169,7 @@ gss_eap_radius_attr_provider::initFromGssContext(const gss_eap_attr_ctx *manager if (gssCtx != GSS_C_NO_CONTEXT) { if (gssCtx->acceptorCtx.avps != NULL) { - m_avps = copyAvps(gssCtx->acceptorCtx.avps); + m_avps = paircopy(gssCtx->acceptorCtx.avps); if (m_avps == NULL) return false; } @@ -172,21 +192,21 @@ alreadyAddedAttributeP(std::vector &attrs, VALUE_PAIR *vp) } static bool -isHiddenAttributeP(int attrid, int vendor) +isHiddenAttributeP(int attrid, uint16_t vendor) { bool ret = false; switch (vendor) { - case VENDOR_ID_MICROSOFT: + case VENDORPEC_MS: switch (attrid) { - case VENDOR_ATTR_MS_MPPE_SEND_KEY: - case VENDOR_ATTR_MS_MPPE_RECV_KEY: + case PW_MS_MPPE_SEND_KEY: + case PW_MS_MPPE_RECV_KEY: ret = true; break; default: break; } - case VENDOR_ID_UKERNA: + case VENDORPEC_UKERNA: ret = true; break; default: @@ -248,11 +268,10 @@ gss_eap_radius_attr_provider::getAttribute(const gss_buffer_t attr, { OM_uint32 tmpMinor; gss_buffer_desc strAttr = GSS_C_EMPTY_BUFFER; - DICT_ATTR *d; + DICT_ATTR *da; int attrid; char *s; - /* XXX vendor */ duplicateBuffer(*attr, &strAttr); s = (char *)strAttr.value; @@ -265,12 +284,12 @@ gss_eap_radius_attr_provider::getAttribute(const gss_buffer_t attr, if (isdigit(*s)) { attrid = strtoul(s, NULL, 10); } else { - d = rc_dict_findattr(m_rh, (char *)s); - if (d == NULL) { + da = dict_attrbyname(s); + if (da == NULL) { gss_release_buffer(&tmpMinor, &strAttr); return false; } - attrid = d->value; + attrid = da->attr; } gss_release_buffer(&tmpMinor, &strAttr); @@ -279,42 +298,18 @@ gss_eap_radius_attr_provider::getAttribute(const gss_buffer_t attr, value, display_value, more); } -static bool -isPrintableAttributeP(VALUE_PAIR *vp) -{ - size_t i; - int gotChar = 0; - - for (i = 0; i < sizeof(vp->strvalue); i++) { - if (gotChar && vp->strvalue[i] == '\0') - return true; - - if (!isprint(vp->strvalue[i])) - return false; - - if (!gotChar) - gotChar++; - } - - return true; -} - bool -gss_eap_radius_attr_provider::getAttribute(int attrid, - int vendor, +gss_eap_radius_attr_provider::getAttribute(uint16_t vattrid, + uint16_t vendor, int *authenticated, int *complete, gss_buffer_t value, gss_buffer_t display_value, int *more) const { - OM_uint32 tmpMinor; + uint32_t attrid = VENDORATTR(vendor, vattrid); 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; @@ -324,11 +319,11 @@ gss_eap_radius_attr_provider::getAttribute(int attrid, if (i == -1) i = 0; - for (vp = rc_avpair_get(m_avps, attrid, vendor); + for (vp = pairfind(m_avps, 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; } @@ -337,27 +332,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); } @@ -371,15 +361,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_avps, attribute, vendor, value, TRUE); if (authenticated != NULL) *authenticated = m_authenticated; @@ -390,7 +380,7 @@ gss_eap_radius_attr_provider::getFragmentedAttribute(int attribute, } bool -gss_eap_radius_attr_provider::getAttribute(int attrid, +gss_eap_radius_attr_provider::getAttribute(uint32_t attrid, int *authenticated, int *complete, gss_buffer_t value, @@ -410,14 +400,14 @@ gss_eap_radius_attr_provider::mapToAny(int authenticated, if (authenticated && !m_authenticated) return (gss_any_t)NULL; - return (gss_any_t)copyAvps(m_avps); + return (gss_any_t)paircopy(m_avps); } void gss_eap_radius_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id, gss_any_t input) const { - rc_avpair_free((VALUE_PAIR *)input); + pairfree((VALUE_PAIR **)&input); } bool @@ -442,42 +432,76 @@ 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, + rs_handle *rh, + VALUE_PAIR **vps, + uint16_t vattrid, + uint16_t vendor, + gss_buffer_t buffer) +{ + uint16_t attrid = VENDORATTR(vendor, vattrid); + unsigned char *p = (unsigned char *)buffer->value; + size_t remain = buffer->length; + + do { + VALUE_PAIR *vp; + size_t n = remain; + + if (n > MAX_STRING_LEN) + n = MAX_STRING_LEN; + + vp = paircreate(attrid, PW_TYPE_OCTETS); + if (vp == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + memcpy(vp->vp_octets, p, n); + pairadd(vps, vp); + + p += n; + remain -= n; + } while (remain != 0); return GSS_S_COMPLETE; } OM_uint32 -getBufferFromAvps(OM_uint32 *minor, - VALUE_PAIR *vps, - int type, - int vendor, - gss_buffer_t buffer, - int concat) +gssEapRadiusGetRawAvp(OM_uint32 *minor, + VALUE_PAIR *vps, + uint16_t type, + uint16_t vendor, + VALUE_PAIR **vp) +{ + uint16_t attr = VENDORATTR(vendor, type); + + *vp = pairfind(vps, attr); + + return (*vp == NULL) ? GSS_S_UNAVAILABLE : GSS_S_COMPLETE; +} + +OM_uint32 +gssEapRadiusGetAvp(OM_uint32 *minor, + VALUE_PAIR *vps, + uint16_t type, + uint16_t vendor, + gss_buffer_t buffer, + int concat) { VALUE_PAIR *vp; unsigned char *p; + uint32_t attr = VENDORATTR(vendor, type); buffer->length = 0; buffer->value = NULL; - vp = rc_avpair_get(vps, type, vendor); + vp = pairfind(vps, attr); if (vp == NULL) 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) { @@ -487,11 +511,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; @@ -513,24 +537,48 @@ gssEapRadiusAttrProviderFinalize(OM_uint32 *minor) } OM_uint32 -gssEapRadiusAllocHandle(OM_uint32 *minor, - const gss_cred_id_t cred, - gss_ctx_id_t ctx) +gssEapRadiusMapError(OM_uint32 *minor, + struct rs_error *err) +{ + if (err != NULL) + rs_err_code(err, 1); + + return GSS_S_FAILURE; +} + +OM_uint32 +gssEapRadiusAllocConn(OM_uint32 *minor, + const gss_cred_id_t cred, + gss_ctx_id_t ctx) { + struct gss_eap_acceptor_ctx *actx = &ctx->acceptorCtx; const char *configFile = NULL; + struct rs_error *err; - assert(ctx->acceptorCtx.radHandle == NULL); + assert(actx->radHandle == NULL); + assert(actx->radConn == NULL); if (cred != GSS_C_NO_CREDENTIAL && cred->radiusConfigFile != NULL) configFile = cred->radiusConfigFile; - if (radiusAllocHandle(configFile, &ctx->acceptorCtx.radHandle) != 0) - return GSS_S_FAILURE; + err = radiusAllocHandle(configFile, &actx->radHandle); + if (err != NULL || actx->radHandle == NULL) { + return gssEapRadiusMapError(minor, err); + } - /* XXX TODO allocate connection handle */ + if (rs_conn_create(actx->radHandle, &actx->radConn, "gss-eap") != 0) { + return gssEapRadiusMapError(minor, rs_err_conn_pop(actx->radConn)); + } - /* XXX TODO select based on acceptorCtx.radServer */ + /* XXX TODO rs_conn_select_server does not exist yet */ +#if 0 + if (actx->radServer != NULL) { + if (rs_conn_select_server(actx->radConn, actx->radServer) != 0) + return gssEapRadiusMapError(minor, rs_err_conn_pop(actx->radConn)); + } +#endif + *minor = 0; return GSS_S_COMPLETE; } @@ -544,13 +592,13 @@ avpSize(const VALUE_PAIR *vp) size_t size = 4 + 1; if (vp != NULL) - size += (vp->type == PW_TYPE_STRING) ? vp->lvalue : 4; + size += vp->length; return size; } static bool -avpExport(rc_handle *rh, +avpExport(rs_handle *rh, const VALUE_PAIR *vp, unsigned char **pBuffer, size_t *pRemain) @@ -562,13 +610,18 @@ avpExport(rc_handle *rh, store_uint32_be(vp->attribute, p); - if (vp->type == PW_TYPE_STRING) { - assert(vp->lvalue <= AUTH_STRING_LEN); - p[4] = (uint8_t)vp->lvalue; - memcpy(p + 5, vp->strvalue, vp->lvalue); - } else { + switch (vp->type) { + case PW_TYPE_INTEGER: + case PW_TYPE_IPADDR: + case PW_TYPE_DATE: p[4] = 4; store_uint32_be(vp->lvalue, p + 5); + break; + default: + assert(vp->length <= MAX_STRING_LEN); + p[4] = (uint8_t)vp->length; + memcpy(p + 5, vp->vp_octets, vp->length); + break; } *pBuffer += 5 + p[4]; @@ -579,56 +632,64 @@ avpExport(rc_handle *rh, } static bool -avpImport(rc_handle *rh, +avpImport(rs_handle *rh, VALUE_PAIR **pVp, unsigned char **pBuffer, size_t *pRemain) { unsigned char *p = *pBuffer; size_t remain = *pRemain; - VALUE_PAIR *vp; - DICT_ATTR *d; + VALUE_PAIR *vp = NULL; + DICT_ATTR *da; + OM_uint32 attrid; if (remain < avpSize(NULL)) - return false; - - vp = (VALUE_PAIR *)GSSEAP_CALLOC(1, sizeof(*vp)); - if (vp == NULL) { - throw new std::bad_alloc; - return false; - } + goto fail; - vp->attribute = load_uint32_be(p); + attrid = load_uint32_be(p); p += 4; remain -= 4; - d = rc_dict_getattr(rh, vp->attribute); - if (d == NULL) + da = dict_attrbyvalue(attrid); + if (da == NULL) goto fail; - assert(sizeof(vp->name) == sizeof(d->name)); - strcpy(vp->name, d->name); - vp->type = d->type; + vp = pairalloc(da); + if (vp == NULL) { + throw new std::bad_alloc; + goto fail; + } if (remain < p[0]) goto fail; - if (vp->type == PW_TYPE_STRING) { - if (p[0] > AUTH_STRING_LEN) - goto fail; - - vp->lvalue = (uint32_t)p[0]; - memcpy(vp->strvalue, p + 1, vp->lvalue); - vp->strvalue[vp->lvalue] = '\0'; - p += 1 + vp->lvalue; - remain -= 1 + vp->lvalue; - } else { + switch (vp->type) { + case PW_TYPE_INTEGER: + case PW_TYPE_IPADDR: + case PW_TYPE_DATE: if (p[0] != 4) goto fail; + vp->length = 4; vp->lvalue = load_uint32_be(p + 1); p += 5; remain -= 5; + break; + case PW_TYPE_STRING: + /* check enough room to NUL terminate */ + if (p[0] >= MAX_STRING_LEN) + goto fail; + /* fallthrough */ + default: + vp->length = (uint32_t)p[0]; + memcpy(vp->vp_octets, p + 1, vp->length); + + if (vp->type == PW_TYPE_STRING) + vp->vp_strvalue[vp->length] = '\0'; + + p += 1 + vp->length; + remain -= 1 + vp->length; + break; } *pVp = vp; @@ -638,7 +699,7 @@ avpImport(rc_handle *rh, return true; fail: - GSSEAP_FREE(vp); + pairbasicfree(vp); return false; } @@ -742,7 +803,7 @@ gss_eap_radius_attr_provider::getExpiryTime(void) const { VALUE_PAIR *vp; - vp = rc_avpair_get(m_avps, PW_SESSION_TIMEOUT, 0); + vp = pairfind(m_avps, PW_SESSION_TIMEOUT); if (vp == NULL || vp->lvalue == 0) return 0; diff --git a/util_radius.h b/util_radius.h index a7bb03c..c505b2a 100644 --- a/util_radius.h +++ b/util_radius.h @@ -66,22 +66,22 @@ public: bool initFromBuffer(const gss_eap_attr_ctx *ctx, const gss_buffer_t buffer); - bool getAttribute(int attribute, + bool getAttribute(uint32_t attribute, int *authenticated, int *complete, gss_buffer_t value, gss_buffer_t display_value, int *more) const; - bool getAttribute(int attribute, - int vendor, + bool getAttribute(uint16_t attribute, + uint16_t vendor, int *authenticated, int *complete, gss_buffer_t value, gss_buffer_t display_value, int *more) const; - bool getFragmentedAttribute(int attribute, - int vendor, + bool getFragmentedAttribute(uint16_t attribute, + uint16_t vendor, int *authenticated, int *complete, gss_buffer_t value) const; @@ -97,12 +97,11 @@ public: private: bool allocRadHandle(const std::string &configFile); - static VALUE_PAIR *copyAvps(const VALUE_PAIR *in); const VALUE_PAIR *getAvps(void) const { return m_avps; } - rc_handle *m_rh; + struct rs_handle *m_rh; VALUE_PAIR *m_avps; bool m_authenticated; std::string m_configFile; @@ -113,46 +112,55 @@ extern "C" { #endif OM_uint32 -addAvpFromBuffer(OM_uint32 *minor, - rc_handle *rh, - VALUE_PAIR **vp, - int type, - int vendor, - gss_buffer_t buffer); +gssEapRadiusAddAvp(OM_uint32 *minor, + struct rs_handle *rh, + VALUE_PAIR **vp, + uint16_t type, + uint16_t vendor, + gss_buffer_t buffer); 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 type, + uint16_t vendor, + gss_buffer_t buffer, + int concat); + +OM_uint32 +gssEapRadiusGetRawAvp(OM_uint32 *minor, + VALUE_PAIR *vps, + uint16_t type, + uint16_t vendor, + VALUE_PAIR **vp); OM_uint32 gssEapRadiusAttrProviderInit(OM_uint32 *minor); OM_uint32 gssEapRadiusAttrProviderFinalize(OM_uint32 *minor); OM_uint32 -gssEapRadiusAllocHandle(OM_uint32 *minor, - const gss_cred_id_t cred, - gss_ctx_id_t ctx); +gssEapRadiusAllocConn(OM_uint32 *minor, + const gss_cred_id_t cred, + gss_ctx_id_t ctx); + +OM_uint32 +gssEapRadiusMapError(OM_uint32 *minor, + struct rs_error *err); -#define RC_CONFIG_FILE SYSCONFDIR "/radiusclient/radiusclient.conf" +#define RS_CONFIG_FILE SYSCONFDIR "/radsec.conf" +#define RS_DICT_FILE DATAROOTDIR "/freeradius/dictionary" -/* RFC 2548 - Microsoft Vendor-specific RADIUS Attributes */ -#define VENDOR_ID_MICROSOFT 311 +#define VENDORPEC_MS 311 /* RFC 2548 */ -enum { VENDOR_ATTR_MS_MPPE_SEND_KEY = 16, - VENDOR_ATTR_MS_MPPE_RECV_KEY = 17 -}; +#define PW_MS_MPPE_SEND_KEY 16 +#define PW_MS_MPPE_RECV_KEY 17 -#define VENDOR_ID_UKERNA 25622 +#define VENDORPEC_UKERNA 25622 -enum { VENDOR_ATTR_GSS_ACCEPTOR_SERVICE_NAME = 128, - VENDOR_ATTR_GSS_ACCEPTOR_HOST_NAME, - VENDOR_ATTR_GSS_ACCEPTOR_SERVICE_SPECIFIC, - VENDOR_ATTR_GSS_ACCEPTOR_REALM_NAME, - VENDOR_ATTR_SAML_AAA_ASSERTION -}; +#define PW_GSS_ACCEPTOR_SERVICE_NAME 128 +#define PW_GSS_ACCEPTOR_HOST_NAME 129 +#define PW_GSS_ACCEPTOR_SERVICE_SPECIFIC 130 +#define PW_GSS_ACCEPTOR_REALM_NAME 131 +#define PW_SAML_AAA_ASSERTION 132 #ifdef __cplusplus } diff --git a/util_saml.cpp b/util_saml.cpp index 0f493fe..f9a74ee 100644 --- a/util_saml.cpp +++ b/util_saml.cpp @@ -105,8 +105,8 @@ gss_eap_saml_assertion_provider::initFromGssContext(const gss_eap_attr_ctx *mana radius = static_cast (m_manager->getProvider(ATTR_TYPE_RADIUS)); if (radius != NULL && - radius->getFragmentedAttribute(VENDOR_ATTR_SAML_AAA_ASSERTION, - VENDOR_ID_UKERNA, + radius->getFragmentedAttribute(PW_SAML_AAA_ASSERTION, + VENDORPEC_UKERNA, &authenticated, &complete, &value)) { setAssertion(&value, authenticated); gss_release_buffer(&minor, &value); -- 2.1.4