2 * Copyright (c) 2010, JANET(UK)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of JANET(UK) nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #include "gssapiP_eap.h"
35 static gss_buffer_desc radiusUrnPrefix = {
36 sizeof("urn:x-radius:") - 1,
37 (void *)"urn:x-radius:"
41 radiusAllocHandle(const char *configFile,
49 if (configFile == NULL || configFile[0] == '\0')
50 configFile = RC_CONFIG_FILE;
52 rh = rc_read_config((char *)configFile);
58 ret = rc_read_dictionary(rh, rc_conf_str(rh, (char *)"dictionary"));
69 gss_eap_radius_attr_provider::copyAvps(const VALUE_PAIR *src)
72 VALUE_PAIR *dst = NULL, **pDst = &dst;
74 for (vp = src; vp != NULL; vp = vp->next) {
77 vp2 = (VALUE_PAIR *)GSSEAP_CALLOC(1, sizeof(*vp2));
82 memcpy(vp2, vp, sizeof(*vp));
91 gss_eap_radius_attr_provider::gss_eap_radius_attr_provider(void)
95 m_authenticated = false;
98 gss_eap_radius_attr_provider::~gss_eap_radius_attr_provider(void)
101 rc_config_free(m_rh);
103 rc_avpair_free(m_avps);
107 gss_eap_radius_attr_provider::allocRadHandle(const std::string &configFile)
109 m_configFile.assign(configFile);
111 return (radiusAllocHandle(m_configFile.c_str(), &m_rh) == 0);
115 gss_eap_radius_attr_provider::initFromExistingContext(const gss_eap_attr_ctx *manager,
116 const gss_eap_attr_provider *ctx)
118 const gss_eap_radius_attr_provider *radius;
120 if (!gss_eap_attr_provider::initFromExistingContext(manager, ctx))
123 radius = static_cast<const gss_eap_radius_attr_provider *>(ctx);
125 if (!allocRadHandle(radius->m_configFile))
128 if (radius->m_avps != NULL)
129 m_avps = copyAvps(radius->getAvps());
135 gss_eap_radius_attr_provider::initFromGssContext(const gss_eap_attr_ctx *manager,
136 const gss_cred_id_t gssCred,
137 const gss_ctx_id_t gssCtx)
139 std::string configFile(RC_CONFIG_FILE);
141 if (!gss_eap_attr_provider::initFromGssContext(manager, gssCred, gssCtx))
144 if (gssCred != GSS_C_NO_CREDENTIAL && gssCred->radiusConfigFile != NULL)
145 configFile.assign(gssCred->radiusConfigFile);
147 if (!allocRadHandle(configFile))
150 if (gssCtx != GSS_C_NO_CONTEXT) {
151 if (gssCtx->acceptorCtx.avps != NULL) {
152 m_avps = copyAvps(gssCtx->acceptorCtx.avps);
162 alreadyAddedAttributeP(std::vector <std::string> &attrs, VALUE_PAIR *vp)
164 for (std::vector<std::string>::const_iterator a = attrs.begin();
167 if (strcmp(vp->name, (*a).c_str()) == 0)
175 isHiddenAttributeP(int attrid, int vendor)
180 case VENDOR_ID_MICROSOFT:
182 case VENDOR_ATTR_MS_MPPE_SEND_KEY:
183 case VENDOR_ATTR_MS_MPPE_RECV_KEY:
189 case VENDOR_ID_UKERNA:
200 gss_eap_radius_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute, void *data) const
203 std::vector <std::string> seen;
205 for (vp = m_avps; vp != NULL; vp = vp->next) {
206 gss_buffer_desc attribute;
208 if (isHiddenAttributeP(ATTRID(vp->attribute), VENDOR(vp->attribute)))
211 if (alreadyAddedAttributeP(seen, vp))
214 snprintf(attrid, sizeof(attrid), "%s%d",
215 (char *)radiusUrnPrefix.value, vp->attribute);
217 attribute.value = attrid;
218 attribute.length = strlen(attrid);
220 if (!addAttribute(this, &attribute, data))
223 seen.push_back(std::string(vp->name));
230 gss_eap_radius_attr_provider::setAttribute(int complete,
231 const gss_buffer_t attr,
232 const gss_buffer_t value)
237 gss_eap_radius_attr_provider::deleteAttribute(const gss_buffer_t value)
242 gss_eap_radius_attr_provider::getAttribute(const gss_buffer_t attr,
246 gss_buffer_t display_value,
250 gss_buffer_desc strAttr = GSS_C_EMPTY_BUFFER;
256 duplicateBuffer(*attr, &strAttr);
257 s = (char *)strAttr.value;
259 if (attr->length < radiusUrnPrefix.length ||
260 memcmp(s, radiusUrnPrefix.value, radiusUrnPrefix.length) != 0)
263 s += radiusUrnPrefix.length;
266 attrid = strtoul(s, NULL, 10);
268 d = rc_dict_findattr(m_rh, (char *)s);
270 gss_release_buffer(&tmpMinor, &strAttr);
276 gss_release_buffer(&tmpMinor, &strAttr);
278 return getAttribute(attrid, authenticated, complete,
279 value, display_value, more);
283 isPrintableAttributeP(VALUE_PAIR *vp)
288 for (i = 0; i < sizeof(vp->strvalue); i++) {
289 if (gotChar && vp->strvalue[i] == '\0')
292 if (!isprint(vp->strvalue[i]))
303 gss_eap_radius_attr_provider::getAttribute(int attrid,
308 gss_buffer_t display_value,
313 int i = *more, count = 0;
314 char name[NAME_LENGTH + 1];
315 char displayString[AUTH_STRING_LEN + 1];
316 gss_buffer_desc valueBuf = GSS_C_EMPTY_BUFFER;
317 gss_buffer_desc displayBuf = GSS_C_EMPTY_BUFFER;
321 if (isHiddenAttributeP(attrid, vendor))
327 for (vp = rc_avpair_get(m_avps, attrid, vendor);
329 vp = rc_avpair_get(vp->next, attrid, vendor)) {
331 if (rc_avpair_get(vp->next, attrid, vendor) != NULL)
337 if (vp == NULL && *more == 0)
340 if (vp->type == PW_TYPE_STRING) {
341 valueBuf.value = (void *)vp->strvalue;
342 valueBuf.length = vp->lvalue;
344 valueBuf.value = (void *)&vp->lvalue;
348 if (value != GSS_C_NO_BUFFER)
349 duplicateBuffer(valueBuf, value);
351 if (display_value != GSS_C_NO_BUFFER &&
352 isPrintableAttributeP(vp)) {
353 if (rc_avpair_tostr(m_rh, vp, name, NAME_LENGTH,
354 displayString, AUTH_STRING_LEN) != 0) {
355 gss_release_buffer(&tmpMinor, value);
359 displayBuf.value = (void *)displayString;
360 displayBuf.length = strlen(displayString);
362 duplicateBuffer(displayBuf, display_value);
365 if (authenticated != NULL)
366 *authenticated = m_authenticated;
367 if (complete != NULL)
374 gss_eap_radius_attr_provider::getFragmentedAttribute(int attribute,
378 gss_buffer_t value) const
380 OM_uint32 major, minor;
382 major = getBufferFromAvps(&minor, m_avps, attribute, vendor, value, TRUE);
384 if (authenticated != NULL)
385 *authenticated = m_authenticated;
386 if (complete != NULL)
389 return !GSS_ERROR(major);
393 gss_eap_radius_attr_provider::getAttribute(int attrid,
397 gss_buffer_t display_value,
401 return getAttribute(ATTRID(attrid), VENDOR(attrid),
402 authenticated, complete,
403 value, display_value, more);
407 gss_eap_radius_attr_provider::mapToAny(int authenticated,
408 gss_buffer_t type_id) const
410 if (authenticated && !m_authenticated)
411 return (gss_any_t)NULL;
413 return (gss_any_t)copyAvps(m_avps);
417 gss_eap_radius_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id,
418 gss_any_t input) const
420 rc_avpair_free((VALUE_PAIR *)input);
424 gss_eap_radius_attr_provider::init(void)
426 gss_eap_attr_ctx::registerProvider(ATTR_TYPE_RADIUS,
427 "urn:ietf:params:gss-eap:radius-avp",
428 gss_eap_radius_attr_provider::createAttrContext);
433 gss_eap_radius_attr_provider::finalize(void)
435 gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_RADIUS);
438 gss_eap_attr_provider *
439 gss_eap_radius_attr_provider::createAttrContext(void)
441 return new gss_eap_radius_attr_provider;
445 addAvpFromBuffer(OM_uint32 *minor,
452 if (rc_avpair_add(rh, vp, type,
453 buffer->value, buffer->length, vendor) == NULL) {
454 return GSS_S_FAILURE;
457 return GSS_S_COMPLETE;
461 getBufferFromAvps(OM_uint32 *minor,
472 buffer->value = NULL;
474 vp = rc_avpair_get(vps, type, vendor);
476 return GSS_S_UNAVAILABLE;
479 buffer->length += vp->lvalue;
480 } while (concat && (vp = rc_avpair_get(vp->next, type, vendor)) != NULL);
482 buffer->value = GSSEAP_MALLOC(buffer->length);
483 if (buffer->value == NULL) {
485 return GSS_S_FAILURE;
488 p = (unsigned char *)buffer->value;
490 for (vp = rc_avpair_get(vps, type, vendor);
491 concat && vp != NULL;
492 vp = rc_avpair_get(vp->next, type, vendor)) {
493 memcpy(p, vp->strvalue, vp->lvalue);
498 return GSS_S_COMPLETE;
502 gssEapRadiusAttrProviderInit(OM_uint32 *minor)
504 return gss_eap_radius_attr_provider::init()
505 ? GSS_S_COMPLETE : GSS_S_FAILURE;
509 gssEapRadiusAttrProviderFinalize(OM_uint32 *minor)
511 gss_eap_radius_attr_provider::finalize();
512 return GSS_S_COMPLETE;
516 gssEapRadiusAllocHandle(OM_uint32 *minor,
517 const gss_cred_id_t cred,
520 const char *configFile = NULL;
522 assert(ctx->acceptorCtx.radHandle == NULL);
524 if (cred != GSS_C_NO_CREDENTIAL && cred->radiusConfigFile != NULL)
525 configFile = cred->radiusConfigFile;
527 if (radiusAllocHandle(configFile, &ctx->acceptorCtx.radHandle) != 0)
528 return GSS_S_FAILURE;
530 /* XXX TODO allocate connection handle */
532 /* XXX TODO select based on acceptorCtx.radServer */
534 return GSS_S_COMPLETE;
539 * 4 octet NBO attribute ID | 4 octet attribute length | attribute data
542 avpSize(const VALUE_PAIR *vp)
547 size += (vp->type == PW_TYPE_STRING) ? vp->lvalue : 4;
553 avpExport(rc_handle *rh,
554 const VALUE_PAIR *vp,
555 unsigned char **pBuffer,
558 unsigned char *p = *pBuffer;
559 size_t remain = *pRemain;
561 assert(remain >= avpSize(vp));
563 store_uint32_be(vp->attribute, p);
565 if (vp->type == PW_TYPE_STRING) {
566 assert(vp->lvalue <= AUTH_STRING_LEN);
567 p[4] = (uint8_t)vp->lvalue;
568 memcpy(p + 5, vp->strvalue, vp->lvalue);
571 store_uint32_be(vp->lvalue, p + 5);
574 *pBuffer += 5 + p[4];
575 *pRemain -= 5 + p[4];
582 avpImport(rc_handle *rh,
584 unsigned char **pBuffer,
587 unsigned char *p = *pBuffer;
588 size_t remain = *pRemain;
592 if (remain < avpSize(NULL))
595 vp = (VALUE_PAIR *)GSSEAP_CALLOC(1, sizeof(*vp));
597 throw new std::bad_alloc;
601 vp->attribute = load_uint32_be(p);
605 d = rc_dict_getattr(rh, vp->attribute);
609 assert(sizeof(vp->name) == sizeof(d->name));
610 strcpy(vp->name, d->name);
616 if (vp->type == PW_TYPE_STRING) {
617 if (p[0] > AUTH_STRING_LEN)
620 vp->lvalue = (uint32_t)p[0];
621 memcpy(vp->strvalue, p + 1, vp->lvalue);
622 vp->strvalue[vp->lvalue] = '\0';
624 remain -= 1 + vp->lvalue;
629 vp->lvalue = load_uint32_be(p + 1);
646 gss_eap_radius_attr_provider::initFromBuffer(const gss_eap_attr_ctx *ctx,
647 const gss_buffer_t buffer)
649 unsigned char *p = (unsigned char *)buffer->value;
650 size_t remain = buffer->length;
651 OM_uint32 configFileLen, count;
652 VALUE_PAIR **pNext = &m_avps;
654 if (!gss_eap_attr_provider::initFromBuffer(ctx, buffer))
660 configFileLen = load_uint32_be(p);
664 if (remain < configFileLen)
667 std::string configFile((char *)p, configFileLen);
669 remain -= configFileLen;
671 if (!allocRadHandle(configFile))
677 count = load_uint32_be(p);
684 if (!avpImport(m_rh, &attr, &p, &remain))
691 } while (remain != 0);
700 gss_eap_radius_attr_provider::exportToBuffer(gss_buffer_t buffer) const
705 size_t remain = 4 + m_configFile.length() + 4;
707 for (vp = m_avps; vp != NULL; vp = vp->next) {
708 remain += avpSize(vp);
712 buffer->value = GSSEAP_MALLOC(remain);
713 if (buffer->value == NULL) {
714 throw new std::bad_alloc;
717 buffer->length = remain;
719 p = (unsigned char *)buffer->value;
721 store_uint32_be(m_configFile.length(), p);
725 memcpy(p, m_configFile.c_str(), m_configFile.length());
726 p += m_configFile.length();
727 remain -= m_configFile.length();
729 store_uint32_be(count, p);
733 for (vp = m_avps; vp != NULL; vp = vp->next) {
734 avpExport(m_rh, vp, &p, &remain);
741 gss_eap_radius_attr_provider::getExpiryTime(void) const
745 vp = rc_avpair_get(m_avps, PW_SESSION_TIMEOUT, 0);
746 if (vp == NULL || vp->lvalue == 0)
749 return time(NULL) + vp->lvalue;