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,
48 if (configFile == NULL || configFile[0] == '\0')
49 configFile = RC_CONFIG_FILE;
51 rh = rc_read_config((char *)configFile);
57 if (rc_read_dictionary(rh, rc_conf_str(rh, (char *)"dictionary")) != 0) {
67 gss_eap_radius_attr_provider::copyAvps(const VALUE_PAIR *src)
70 VALUE_PAIR *dst = NULL, **pDst = &dst;
72 for (vp = src; vp != NULL; vp = vp->next) {
75 vp2 = (VALUE_PAIR *)GSSEAP_CALLOC(1, sizeof(*vp2));
80 memcpy(vp2, vp, sizeof(*vp));
89 gss_eap_radius_attr_provider::gss_eap_radius_attr_provider(void)
93 m_authenticated = false;
96 gss_eap_radius_attr_provider::~gss_eap_radius_attr_provider(void)
101 rc_avpair_free(m_avps);
105 gss_eap_radius_attr_provider::allocRadHandle(const std::string &configFile)
107 m_configFile.assign(configFile);
109 return radiusAllocHandle(m_configFile.c_str(), &m_rh);
113 gss_eap_radius_attr_provider::initFromExistingContext(const gss_eap_attr_ctx *manager,
114 const gss_eap_attr_provider *ctx)
116 const gss_eap_radius_attr_provider *radius;
118 if (!gss_eap_attr_provider::initFromExistingContext(manager, ctx))
121 radius = static_cast<const gss_eap_radius_attr_provider *>(ctx);
123 if (!allocRadHandle(radius->m_configFile))
126 if (radius->m_avps != NULL)
127 m_avps = copyAvps(radius->getAvps());
133 gss_eap_radius_attr_provider::initFromGssContext(const gss_eap_attr_ctx *manager,
134 const gss_cred_id_t gssCred,
135 const gss_ctx_id_t gssCtx)
137 std::string configFile(RC_CONFIG_FILE);
139 if (!gss_eap_attr_provider::initFromGssContext(manager, gssCred, gssCtx))
142 if (gssCred != GSS_C_NO_CREDENTIAL && gssCred->radiusConfigFile != NULL)
143 configFile.assign(gssCred->radiusConfigFile);
145 if (!allocRadHandle(configFile))
148 if (gssCtx != GSS_C_NO_CONTEXT) {
149 if (gssCtx->acceptorCtx.avps != NULL) {
150 m_avps = copyAvps(gssCtx->acceptorCtx.avps);
160 alreadyAddedAttributeP(std::vector <std::string> &attrs, VALUE_PAIR *vp)
162 for (std::vector<std::string>::const_iterator a = attrs.begin();
165 if (strcmp(vp->name, (*a).c_str()) == 0)
173 isHiddenAttributeP(int attrid, int vendor)
178 case VENDOR_ID_MICROSOFT:
180 case VENDOR_ATTR_MS_MPPE_SEND_KEY:
181 case VENDOR_ATTR_MS_MPPE_RECV_KEY:
187 case VENDOR_ID_UKERNA:
198 gss_eap_radius_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute, void *data) const
201 std::vector <std::string> seen;
203 for (vp = m_avps; vp != NULL; vp = vp->next) {
204 gss_buffer_desc attribute;
206 if (isHiddenAttributeP(ATTRID(vp->attribute), VENDOR(vp->attribute)))
209 if (alreadyAddedAttributeP(seen, vp))
212 snprintf(attrid, sizeof(attrid), "%s%d",
213 (char *)radiusUrnPrefix.value, vp->attribute);
215 attribute.value = attrid;
216 attribute.length = strlen(attrid);
218 if (!addAttribute(this, &attribute, data))
221 seen.push_back(std::string(vp->name));
228 gss_eap_radius_attr_provider::setAttribute(int complete,
229 const gss_buffer_t attr,
230 const gss_buffer_t value)
235 gss_eap_radius_attr_provider::deleteAttribute(const gss_buffer_t value)
240 gss_eap_radius_attr_provider::getAttribute(const gss_buffer_t attr,
244 gss_buffer_t display_value,
248 gss_buffer_desc strAttr = GSS_C_EMPTY_BUFFER;
254 duplicateBuffer(*attr, &strAttr);
255 s = (char *)strAttr.value;
257 if (attr->length < radiusUrnPrefix.length ||
258 memcmp(s, radiusUrnPrefix.value, radiusUrnPrefix.length) != 0)
261 s += radiusUrnPrefix.length;
264 attrid = strtoul(s, NULL, 10);
266 d = rc_dict_findattr(m_rh, (char *)s);
268 gss_release_buffer(&tmpMinor, &strAttr);
274 gss_release_buffer(&tmpMinor, &strAttr);
276 return getAttribute(attrid, authenticated, complete,
277 value, display_value, more);
281 isPrintableAttributeP(VALUE_PAIR *vp)
286 for (i = 0; i < sizeof(vp->strvalue); i++) {
287 if (gotChar && vp->strvalue[i] == '\0')
290 if (!isprint(vp->strvalue[i]))
301 gss_eap_radius_attr_provider::getAttribute(int attrid,
306 gss_buffer_t display_value,
311 int i = *more, count = 0;
312 char name[NAME_LENGTH + 1];
313 char displayString[AUTH_STRING_LEN + 1];
314 gss_buffer_desc valueBuf = GSS_C_EMPTY_BUFFER;
315 gss_buffer_desc displayBuf = GSS_C_EMPTY_BUFFER;
319 if (isHiddenAttributeP(attrid, vendor))
325 for (vp = rc_avpair_get(m_avps, attrid, vendor);
327 vp = rc_avpair_get(vp->next, attrid, vendor)) {
329 if (rc_avpair_get(vp->next, attrid, vendor) != NULL)
335 if (vp == NULL && *more == 0)
338 if (vp->type == PW_TYPE_STRING) {
339 valueBuf.value = (void *)vp->strvalue;
340 valueBuf.length = vp->lvalue;
342 valueBuf.value = (void *)&vp->lvalue;
346 if (value != GSS_C_NO_BUFFER)
347 duplicateBuffer(valueBuf, value);
349 if (display_value != GSS_C_NO_BUFFER &&
350 isPrintableAttributeP(vp)) {
351 if (rc_avpair_tostr(m_rh, vp, name, NAME_LENGTH,
352 displayString, AUTH_STRING_LEN) != 0) {
353 gss_release_buffer(&tmpMinor, value);
357 displayBuf.value = (void *)displayString;
358 displayBuf.length = strlen(displayString);
360 duplicateBuffer(displayBuf, display_value);
363 if (authenticated != NULL)
364 *authenticated = m_authenticated;
365 if (complete != NULL)
372 gss_eap_radius_attr_provider::getFragmentedAttribute(int attribute,
376 gss_buffer_t value) const
378 OM_uint32 major, minor;
380 major = getBufferFromAvps(&minor, m_avps, attribute, vendor, value, TRUE);
382 if (authenticated != NULL)
383 *authenticated = m_authenticated;
384 if (complete != NULL)
387 return !GSS_ERROR(major);
391 gss_eap_radius_attr_provider::getAttribute(int attrid,
395 gss_buffer_t display_value,
399 return getAttribute(ATTRID(attrid), VENDOR(attrid),
400 authenticated, complete,
401 value, display_value, more);
405 gss_eap_radius_attr_provider::mapToAny(int authenticated,
406 gss_buffer_t type_id) const
408 if (authenticated && !m_authenticated)
409 return (gss_any_t)NULL;
411 return (gss_any_t)copyAvps(m_avps);
415 gss_eap_radius_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id,
416 gss_any_t input) const
418 rc_avpair_free((VALUE_PAIR *)input);
422 gss_eap_radius_attr_provider::init(void)
424 gss_eap_attr_ctx::registerProvider(ATTR_TYPE_RADIUS,
425 "urn:ietf:params:gss-eap:radius-avp",
426 gss_eap_radius_attr_provider::createAttrContext);
431 gss_eap_radius_attr_provider::finalize(void)
433 gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_RADIUS);
436 gss_eap_attr_provider *
437 gss_eap_radius_attr_provider::createAttrContext(void)
439 return new gss_eap_radius_attr_provider;
443 addAvpFromBuffer(OM_uint32 *minor,
450 if (rc_avpair_add(rh, vp, type,
451 buffer->value, buffer->length, vendor) == NULL) {
452 return GSS_S_FAILURE;
455 return GSS_S_COMPLETE;
459 getBufferFromAvps(OM_uint32 *minor,
470 buffer->value = NULL;
472 vp = rc_avpair_get(vps, type, vendor);
474 return GSS_S_UNAVAILABLE;
477 buffer->length += vp->lvalue;
478 } while (concat && (vp = rc_avpair_get(vp->next, type, vendor)) != NULL);
480 buffer->value = GSSEAP_MALLOC(buffer->length);
481 if (buffer->value == NULL) {
483 return GSS_S_FAILURE;
486 p = (unsigned char *)buffer->value;
488 for (vp = rc_avpair_get(vps, type, vendor);
489 concat && vp != NULL;
490 vp = rc_avpair_get(vp->next, type, vendor)) {
491 memcpy(p, vp->strvalue, vp->lvalue);
496 return GSS_S_COMPLETE;
500 gssEapRadiusAttrProviderInit(OM_uint32 *minor)
502 return gss_eap_radius_attr_provider::init()
503 ? GSS_S_COMPLETE : GSS_S_FAILURE;
507 gssEapRadiusAttrProviderFinalize(OM_uint32 *minor)
509 gss_eap_radius_attr_provider::finalize();
510 return GSS_S_COMPLETE;
514 gssEapRadiusAllocHandle(OM_uint32 *minor,
515 const gss_cred_id_t cred,
518 const char *configFile = NULL;
522 if (cred != GSS_C_NO_CREDENTIAL && cred->radiusConfigFile != NULL)
523 configFile = cred->radiusConfigFile;
525 if (!radiusAllocHandle(configFile, pHandle))
526 return GSS_S_FAILURE;
528 return GSS_S_COMPLETE;
533 * 4 octet NBO attribute ID | 4 octet attribute length | attribute data
536 avpSize(const VALUE_PAIR *vp)
541 size += (vp->type == PW_TYPE_STRING) ? vp->lvalue : 4;
547 avpExport(rc_handle *rh,
548 const VALUE_PAIR *vp,
549 unsigned char **pBuffer,
552 unsigned char *p = *pBuffer;
553 size_t remain = *pRemain;
555 assert(remain >= avpSize(vp));
557 store_uint32_be(vp->attribute, p);
559 if (vp->type == PW_TYPE_STRING) {
560 assert(vp->lvalue <= AUTH_STRING_LEN);
561 p[4] = (uint8_t)vp->lvalue;
562 memcpy(p + 5, vp->strvalue, vp->lvalue);
565 store_uint32_be(vp->lvalue, p + 5);
568 *pBuffer += 5 + p[4];
569 *pRemain -= 5 + p[4];
576 avpImport(rc_handle *rh,
578 unsigned char **pBuffer,
581 unsigned char *p = *pBuffer;
582 size_t remain = *pRemain;
586 if (remain < avpSize(NULL))
589 vp = (VALUE_PAIR *)GSSEAP_CALLOC(1, sizeof(*vp));
591 throw new std::bad_alloc;
595 vp->attribute = load_uint32_be(p);
599 d = rc_dict_getattr(rh, vp->attribute);
603 assert(sizeof(vp->name) == sizeof(d->name));
604 strcpy(vp->name, d->name);
610 if (vp->type == PW_TYPE_STRING) {
611 if (p[0] > AUTH_STRING_LEN)
614 vp->lvalue = (uint32_t)p[0];
615 memcpy(vp->strvalue, p + 1, vp->lvalue);
616 vp->strvalue[vp->lvalue] = '\0';
618 remain -= 1 + vp->lvalue;
623 vp->lvalue = load_uint32_be(p + 1);
640 gss_eap_radius_attr_provider::initFromBuffer(const gss_eap_attr_ctx *ctx,
641 const gss_buffer_t buffer)
643 unsigned char *p = (unsigned char *)buffer->value;
644 size_t remain = buffer->length;
645 OM_uint32 configFileLen, count;
646 VALUE_PAIR **pNext = &m_avps;
648 if (!gss_eap_attr_provider::initFromBuffer(ctx, buffer))
654 configFileLen = load_uint32_be(p);
658 if (remain < configFileLen)
661 std::string configFile((char *)p, configFileLen);
663 remain -= configFileLen;
665 if (!allocRadHandle(configFile))
671 count = load_uint32_be(p);
678 if (!avpImport(m_rh, &attr, &p, &remain))
685 } while (remain != 0);
694 gss_eap_radius_attr_provider::exportToBuffer(gss_buffer_t buffer) const
699 size_t remain = 4 + m_configFile.length() + 4;
701 for (vp = m_avps; vp != NULL; vp = vp->next) {
702 remain += avpSize(vp);
706 buffer->value = GSSEAP_MALLOC(remain);
707 if (buffer->value == NULL) {
708 throw new std::bad_alloc;
711 buffer->length = remain;
713 p = (unsigned char *)buffer->value;
715 store_uint32_be(m_configFile.length(), p);
719 memcpy(p, m_configFile.c_str(), m_configFile.length());
720 p += m_configFile.length();
721 remain -= m_configFile.length();
723 store_uint32_be(count, p);
727 for (vp = m_avps; vp != NULL; vp = vp->next) {
728 avpExport(m_rh, vp, &p, &remain);
735 gss_eap_radius_attr_provider::getExpiryTime(void) const
739 vp = rc_avpair_get(m_avps, PW_SESSION_TIMEOUT, 0);
740 if (vp == NULL || vp->lvalue == 0)
743 return time(NULL) + vp->lvalue;