+static bool
+alreadyAddedAttributeP(std::vector <std::string> &attrs, VALUE_PAIR *vp)
+{
+ for (std::vector<std::string>::const_iterator a = attrs.begin();
+ a != attrs.end();
+ ++a) {
+ if (strcmp(vp->name, (*a).c_str()) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+static bool
+isSecretAttributeP(uint16_t attrid, uint16_t vendor)
+{
+ bool bSecretAttribute = false;
+
+ switch (vendor) {
+ case VENDORPEC_MS:
+ switch (attrid) {
+ case PW_MS_MPPE_SEND_KEY:
+ case PW_MS_MPPE_RECV_KEY:
+ bSecretAttribute = true;
+ break;
+ default:
+ break;
+ }
+ 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 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 new std::bad_alloc;
+ return NULL;
+ }
+ *pDst = vpcopy;
+ pDst = &vpcopy->next;
+ }
+
+ return dst;
+}
+
+bool
+gss_eap_radius_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
+ void *data) const
+{
+ VALUE_PAIR *vp;
+ std::vector <std::string> seen;
+
+ for (vp = m_vps; vp != NULL; vp = vp->next) {
+ gss_buffer_desc attribute;
+ char attrid[64];
+
+ /* Don't advertise attributes that are internal to the GSS-EAP mechanism */
+ if (isInternalAttributeP(vp->attribute))
+ continue;
+
+ if (alreadyAddedAttributeP(seen, vp))
+ continue;
+
+ snprintf(attrid, sizeof(attrid), "%s%d",
+ (char *)radiusUrnPrefix.value, vp->attribute);
+
+ attribute.value = attrid;
+ attribute.length = strlen(attrid);
+
+ if (!addAttribute(this, &attribute, data))
+ return false;
+
+ seen.push_back(std::string(vp->name));
+ }
+
+ return true;
+}
+
+uint32_t
+getAttributeId(const gss_buffer_t attr)
+{
+ OM_uint32 tmpMinor;
+ gss_buffer_desc strAttr = GSS_C_EMPTY_BUFFER;
+ DICT_ATTR *da;
+ char *s;
+ uint32_t attrid = 0;
+
+ 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 + radiusUrnPrefix.length;
+
+ if (isdigit(*s)) {
+ attrid = strtoul(s, NULL, 10);
+ } else {
+ da = dict_attrbyname(s);
+ if (da != NULL)
+ attrid = da->attr;
+ }
+
+ gss_release_buffer(&tmpMinor, &strAttr);
+
+ return attrid;
+}
+
+bool
+gss_eap_radius_attr_provider::setAttribute(int complete,
+ uint32_t attrid,
+ const gss_buffer_t value)
+{
+ OM_uint32 major = GSS_S_UNAVAILABLE, minor;
+
+ if (!isSecretAttributeP(attrid) &&
+ !isInternalAttributeP(attrid)) {
+ deleteAttribute(attrid);
+
+ major = gssEapRadiusAddAvp(&minor, &m_vps,
+ ATTRID(attrid), VENDOR(attrid),
+ value);
+ }
+
+ return !GSS_ERROR(major);
+}
+
+bool