+
+OM_uint32
+gssEapRadiusAddAvp(OM_uint32 *minor,
+ VALUE_PAIR **vps,
+ uint16_t attribute,
+ uint16_t vendor,
+ const gss_buffer_t buffer)
+{
+ uint32_t attrid = VENDORATTR(vendor, attribute);
+ unsigned char *p = (unsigned char *)buffer->value;
+ size_t remain = buffer->length;
+
+ do {
+ VALUE_PAIR *vp;
+ size_t n = remain;
+
+ /*
+ * There's an extra byte of padding; RADIUS AVPs can only
+ * be 253 octets.
+ */
+ if (n >= MAX_STRING_LEN)
+ n = MAX_STRING_LEN - 1;
+
+ vp = paircreate(attrid, PW_TYPE_OCTETS);
+ if (vp == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ memcpy(vp->vp_octets, p, n);
+ vp->length = n;
+
+ pairadd(vps, vp);
+
+ p += n;
+ remain -= n;
+ } while (remain != 0);
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gssEapRadiusGetRawAvp(OM_uint32 *minor,
+ VALUE_PAIR *vps,
+ uint16_t attribute,
+ uint16_t vendor,
+ VALUE_PAIR **vp)
+{
+ 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;
+}
+
+static DDF
+avpMarshall(const VALUE_PAIR *vp)
+{
+ DDF obj(NULL);
+
+ obj.addmember("type").integer(vp->attribute);
+
+ assert(vp->length <= MAX_STRING_LEN);
+
+ switch (vp->type) {
+ case PW_TYPE_INTEGER:
+ case PW_TYPE_IPADDR:
+ case PW_TYPE_DATE:
+ obj.addmember("value").integer(vp->lvalue);
+ break;
+ case PW_TYPE_STRING:
+ obj.addmember("value").string(vp->vp_strvalue);
+ break;
+ default: {
+ XMLSize_t len;
+ XMLByte *b64 = xercesc::Base64::encode(vp->vp_octets, vp->length, &len);
+
+ if (b64[len - 1] == '\n')
+ b64[--len] = '\0'; /* XXX there may be embedded newlines */
+
+ obj.addmember("value").string((char *)b64);
+ delete b64;
+ break;
+ }
+ }
+
+ return obj;
+}
+
+static bool
+avpUnmarshall(VALUE_PAIR **pVp, DDF &obj)
+{
+ VALUE_PAIR *vp = NULL;
+ DICT_ATTR *da;
+ uint32_t attrid;
+
+ attrid = obj["type"].integer();
+
+ 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;
+ }
+
+ switch (vp->type) {
+ case PW_TYPE_INTEGER:
+ case PW_TYPE_IPADDR:
+ case PW_TYPE_DATE:
+ vp->length = 4;
+ vp->lvalue = obj["value"].integer();;
+ break;
+ case PW_TYPE_STRING: {
+ const char *str = obj["value"].string();
+ size_t len = strlen(str);
+ if (str == NULL || len >= MAX_STRING_LEN)
+ goto fail;
+
+ vp->length = len;
+ memcpy(vp->vp_strvalue, str, len + 1);
+ break;
+ }
+ case PW_TYPE_OCTETS:
+ default: {
+ XMLSize_t len;
+ const XMLByte *b64 = (const XMLByte *)obj["value"].string();
+ XMLByte *data = xercesc::Base64::decode(b64, &len);
+ if (data == NULL || len >= MAX_STRING_LEN) {
+ delete data;
+ goto fail;
+ }
+
+ vp->length = len;
+ memcpy(vp->vp_octets, data, len);
+ vp->vp_octets[len] = '\0';
+ delete data;
+ break;
+ }
+ }
+
+ *pVp = vp;
+
+ return true;
+
+fail:
+ if (vp != NULL)
+ pairbasicfree(vp);
+ *pVp = NULL;
+ return false;
+}
+
+const char *
+gss_eap_radius_attr_provider::marshallingKey(void) const
+{
+ return "radius";
+}
+
+bool
+gss_eap_radius_attr_provider::unmarshallAndInit(const gss_eap_attr_ctx *ctx,
+ DDF &obj)
+{
+ VALUE_PAIR **pNext = &m_vps;
+
+ if (!gss_eap_attr_provider::unmarshallAndInit(ctx, obj))
+ return false;
+
+ DDF attrs = obj["attributes"];
+ DDF attr = attrs.first();
+
+ while (!attr.isnull()) {
+ VALUE_PAIR *vp;
+
+ if (!avpUnmarshall(&vp, attr))
+ return false;
+
+ *pNext = vp;
+ pNext = &vp->next;
+
+ attr = attrs.next();
+ }
+
+ return true;
+}
+
+DDF
+gss_eap_radius_attr_provider::marshall(void) const
+{
+ DDF obj(NULL);
+ DDF attrs = obj.structure().addmember("attributes").list();
+
+ for (VALUE_PAIR *vp = m_vps; vp != NULL; vp = vp->next) {
+ DDF attr = avpMarshall(vp);
+ attrs.add(attr);
+ }
+
+ return obj;
+}
+
+time_t
+gss_eap_radius_attr_provider::getExpiryTime(void) const
+{
+ VALUE_PAIR *vp;
+
+ vp = pairfind(m_vps, PW_SESSION_TIMEOUT);
+ if (vp == NULL || vp->lvalue == 0)
+ return 0;
+
+ return time(NULL) + vp->lvalue;
+}
+
+OM_uint32
+gssEapRadiusMapError(OM_uint32 *minor,
+ struct rs_error *err)
+{
+ int code;
+
+ assert(err != NULL);
+
+ code = rs_err_code(err, 0);
+
+ if (code == RSE_OK) {
+ *minor = 0;
+ return GSS_S_COMPLETE;
+ }
+
+ *minor = ERROR_TABLE_BASE_rse + code;
+
+ gssEapSaveStatusInfo(*minor, "%s", rs_err_msg(err));
+ rs_err_free(err);
+
+ return GSS_S_FAILURE;
+}