+ 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
+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 = pairfind(vps, attr);
+ if (vp == NULL) {
+ *minor = GSSEAP_NO_SUCH_ATTR;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ do {
+ buffer->length += vp->length;
+ } while (concat && (vp = pairfind(vp->next, attr)) != NULL);
+
+ buffer->value = GSSEAP_MALLOC(buffer->length);
+ if (buffer->value == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ p = (unsigned char *)buffer->value;
+
+ for (vp = pairfind(vps, attr);
+ concat && vp != NULL;
+ vp = pairfind(vp->next, attr)) {
+ memcpy(p, vp->vp_octets, vp->length);
+ p += vp->length;
+ }
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapRadiusFreeAvps(OM_uint32 *minor,
+ VALUE_PAIR **vps)
+{
+ pairfree(vps);
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapRadiusAttrProviderInit(OM_uint32 *minor)
+{
+ 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;
+}
+
+/*
+ * Encoding is:
+ * 4 octet NBO attribute ID | 4 octet attribute length | attribute data
+ */
+static size_t
+avpSize(const VALUE_PAIR *vp)
+{
+ size_t size = 4 + 1;
+
+ if (vp != NULL)
+ size += vp->length;
+
+ return size;
+}
+
+static bool
+avpExport(const VALUE_PAIR *vp,
+ unsigned char **pBuffer,
+ size_t *pRemain)
+{
+ unsigned char *p = *pBuffer;
+ size_t remain = *pRemain;
+
+ assert(remain >= avpSize(vp));
+
+ store_uint32_be(vp->attribute, p);
+
+ 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];
+ *pRemain -= 5 + p[4];
+
+ return true;
+
+}
+
+static bool
+avpImport(VALUE_PAIR **pVp,
+ unsigned char **pBuffer,
+ size_t *pRemain)
+{
+ unsigned char *p = *pBuffer;
+ size_t remain = *pRemain;
+ VALUE_PAIR *vp = NULL;
+ DICT_ATTR *da;
+ uint32_t attrid;
+
+ if (remain < avpSize(NULL))
+ goto fail;
+
+ attrid = load_uint32_be(p);
+ p += 4;
+ remain -= 4;
+
+ da = dict_attrbyvalue(attrid);
+ if (da != NULL) {
+ vp = pairalloc(da);
+ } else {
+ vp = paircreate(attrid, PW_TYPE_STRING);
+ }
+ if (vp == NULL) {
+ throw new std::bad_alloc;
+ goto fail;
+ }
+
+ if (remain < p[0])
+ goto fail;
+
+ 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:
+ default:
+ if (p[0] >= MAX_STRING_LEN)
+ goto fail;
+
+ 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;
+ *pBuffer = p;
+ *pRemain = remain;
+
+ return true;
+
+fail:
+ if (vp != NULL)
+ pairbasicfree(vp);
+ *pVp = NULL;
+ return false;