Eap channel bindings cleanup
[mech_eap.git] / mech_eap / util_radius.cpp
1 /*
2  * Copyright (c) 2011, JANET(UK)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
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.
15  *
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.
19  *
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
30  * SUCH DAMAGE.
31  */
32
33 /*
34  * RADIUS attribute provider implementation.
35  */
36
37 #include "gssapiP_eap.h"
38 #include "util_radius.h"
39 #include "utils/radius_utils.h"
40
41 #ifdef GSSEAP_ENABLE_ACCEPTOR
42
43 /* stuff that should be provided by libradsec/libfreeradius-radius */
44 #define VENDORATTR(vendor, attr)            (((vendor) << 16) | (attr))
45
46 #ifndef ATTRID
47 #define ATTRID(attr)                        ((attr) & 0xFFFF)
48 #endif
49
50 static gss_buffer_desc radiusUrnPrefix = {
51     sizeof("urn:x-radius:") - 1,
52     (void *)"urn:x-radius:"
53 };
54
55 static VALUE_PAIR *copyAvps(const VALUE_PAIR *src);
56
57 gss_eap_radius_attr_provider::gss_eap_radius_attr_provider(void)
58 {
59     m_vps = NULL;
60     m_authenticated = false;
61 }
62
63 gss_eap_radius_attr_provider::~gss_eap_radius_attr_provider(void)
64 {
65     if (m_vps != NULL)
66         pairfree(&m_vps);
67 }
68
69 bool
70 gss_eap_radius_attr_provider::initWithExistingContext(const gss_eap_attr_ctx *manager,
71                                                       const gss_eap_attr_provider *ctx)
72 {
73     const gss_eap_radius_attr_provider *radius;
74
75     if (!gss_eap_attr_provider::initWithExistingContext(manager, ctx))
76         return false;
77
78     radius = static_cast<const gss_eap_radius_attr_provider *>(ctx);
79
80     if (radius->m_vps != NULL)
81         m_vps = copyAvps(const_cast<VALUE_PAIR *>(radius->getAvps()));
82
83     m_authenticated = radius->m_authenticated;
84
85     return true;
86 }
87
88 bool
89 gss_eap_radius_attr_provider::initWithGssContext(const gss_eap_attr_ctx *manager,
90                                                  const gss_cred_id_t gssCred,
91                                                  const gss_ctx_id_t gssCtx)
92 {
93     if (!gss_eap_attr_provider::initWithGssContext(manager, gssCred, gssCtx))
94         return false;
95
96     if (gssCtx != GSS_C_NO_CONTEXT) {
97         if (gssCtx->acceptorCtx.vps != NULL) {
98             m_vps = copyAvps(gssCtx->acceptorCtx.vps);
99             if (m_vps == NULL)
100                 return false;
101
102             /* We assume libradsec validated this for us */
103             GSSEAP_ASSERT(pairfind(m_vps, PW_MESSAGE_AUTHENTICATOR) != NULL);
104             m_authenticated = true;
105         }
106     }
107
108     return true;
109 }
110
111 static bool
112 alreadyAddedAttributeP(std::vector <std::string> &attrs, VALUE_PAIR *vp)
113 {
114     for (std::vector<std::string>::const_iterator a = attrs.begin();
115          a != attrs.end();
116          ++a) {
117         if (strcmp(vp->name, (*a).c_str()) == 0)
118             return true;
119     }
120
121     return false;
122 }
123
124 static bool
125 isSecretAttributeP(uint16_t attrid, uint16_t vendor)
126 {
127     bool bSecretAttribute = false;
128
129     switch (vendor) {
130     case VENDORPEC_MS:
131         switch (attrid) {
132         case PW_MS_MPPE_SEND_KEY:
133         case PW_MS_MPPE_RECV_KEY:
134             bSecretAttribute = true;
135             break;
136         default:
137             break;
138         }
139     default:
140         break;
141     }
142
143     return bSecretAttribute;
144 }
145
146 static bool
147 isSecretAttributeP(uint32_t attribute)
148 {
149     return isSecretAttributeP(ATTRID(attribute), VENDOR(attribute));
150 }
151
152 static bool
153 isInternalAttributeP(uint16_t attrid, uint16_t vendor)
154 {
155     bool bInternalAttribute = false;
156
157     /* should have been filtered */
158     GSSEAP_ASSERT(!isSecretAttributeP(attrid, vendor));
159
160     switch (vendor) {
161     case VENDORPEC_UKERNA:
162         switch (attrid) {
163         case PW_GSS_ACCEPTOR_SERVICE_NAME:
164         case PW_GSS_ACCEPTOR_HOST_NAME:
165         case PW_GSS_ACCEPTOR_SERVICE_SPECIFIC:
166         case PW_GSS_ACCEPTOR_REALM_NAME:
167         case PW_SAML_AAA_ASSERTION:
168             bInternalAttribute = true;
169             break;
170         default:
171             break;
172         }
173         break;
174     default:
175         break;
176     }
177
178     return bInternalAttribute;
179 }
180
181 static bool
182 isInternalAttributeP(uint32_t attribute)
183 {
184     return isInternalAttributeP(ATTRID(attribute), VENDOR(attribute));
185 }
186
187 static bool
188 isFragmentedAttributeP(uint16_t attrid, uint16_t vendor)
189 {
190     /* A bit of a hack for the PAC for now. Should be configurable. */
191     return (vendor == VENDORPEC_UKERNA) &&
192         !isInternalAttributeP(attrid, vendor);
193 }
194
195 static bool
196 isFragmentedAttributeP(uint32_t attribute)
197 {
198     return isFragmentedAttributeP(ATTRID(attribute), VENDOR(attribute));
199 }
200
201 /*
202  * Copy AVP list, same as paircopy except it filters out attributes
203  * containing keys.
204  */
205 static VALUE_PAIR *
206 copyAvps(const VALUE_PAIR *src)
207 {
208     const VALUE_PAIR *vp;
209     VALUE_PAIR *dst = NULL, **pDst = &dst;
210
211     for (vp = src; vp != NULL; vp = vp->next) {
212         VALUE_PAIR *vpcopy;
213
214         if (isSecretAttributeP(vp->attribute))
215             continue;
216
217         vpcopy = paircopyvp(vp);
218         if (vpcopy == NULL) {
219             pairfree(&dst);
220             throw std::bad_alloc();
221         }
222         *pDst = vpcopy;
223         pDst = &vpcopy->next;
224      }
225
226     return dst;
227 }
228
229 bool
230 gss_eap_radius_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
231                                                 void *data) const
232 {
233     VALUE_PAIR *vp;
234     std::vector <std::string> seen;
235
236     for (vp = m_vps; vp != NULL; vp = vp->next) {
237         gss_buffer_desc attribute;
238         char attrid[64];
239
240         /* Don't advertise attributes that are internal to the GSS-EAP mechanism */
241         if (isInternalAttributeP(vp->attribute))
242             continue;
243
244         if (alreadyAddedAttributeP(seen, vp))
245             continue;
246
247         snprintf(attrid, sizeof(attrid), "%s%d",
248             (char *)radiusUrnPrefix.value, vp->attribute);
249
250         attribute.value = attrid;
251         attribute.length = strlen(attrid);
252
253         if (!addAttribute(m_manager, this, &attribute, data))
254             return false;
255
256         seen.push_back(std::string(vp->name));
257     }
258
259     return true;
260 }
261
262 uint32_t
263 getAttributeId(const gss_buffer_t attr)
264 {
265     OM_uint32 tmpMinor;
266     gss_buffer_desc strAttr = GSS_C_EMPTY_BUFFER;
267     DICT_ATTR *da;
268     char *s;
269     uint32_t attrid = 0;
270
271     if (attr->length < radiusUrnPrefix.length ||
272         memcmp(attr->value, radiusUrnPrefix.value, radiusUrnPrefix.length) != 0)
273         return 0;
274
275     /* need to duplicate because attr may not be NUL terminated */
276     duplicateBuffer(*attr, &strAttr);
277     s = (char *)strAttr.value + radiusUrnPrefix.length;
278
279     if (isdigit(*s)) {
280         attrid = strtoul(s, NULL, 10);
281     } else {
282         da = dict_attrbyname(s);
283         if (da != NULL)
284             attrid = da->attr;
285     }
286
287     gss_release_buffer(&tmpMinor, &strAttr);
288
289     return attrid;
290 }
291
292 bool
293 gss_eap_radius_attr_provider::setAttribute(int complete GSSEAP_UNUSED,
294                                            uint32_t attrid,
295                                            const gss_buffer_t value)
296 {
297     OM_uint32 major = GSS_S_UNAVAILABLE, minor;
298
299     if (!isSecretAttributeP(attrid) &&
300         !isInternalAttributeP(attrid)) {
301         deleteAttribute(attrid);
302
303         major = gssEapRadiusAddAvp(&minor, &m_vps,
304                                    ATTRID(attrid), VENDOR(attrid), 
305                                    value);
306     }
307
308     return !GSS_ERROR(major);
309 }
310
311 bool
312 gss_eap_radius_attr_provider::setAttribute(int complete,
313                                            const gss_buffer_t attr,
314                                            const gss_buffer_t value)
315 {
316     uint32_t attrid = getAttributeId(attr);
317
318     if (!attrid)
319         return false;
320
321     return setAttribute(complete, attrid, value);
322 }
323
324 bool
325 gss_eap_radius_attr_provider::deleteAttribute(uint32_t attrid)
326 {
327     if (isSecretAttributeP(attrid) || isInternalAttributeP(attrid) ||
328         pairfind(m_vps, attrid) == NULL)
329         return false;
330
331     pairdelete(&m_vps, attrid);
332
333     return true;
334 }
335
336 bool
337 gss_eap_radius_attr_provider::deleteAttribute(const gss_buffer_t attr)
338 {
339     uint32_t attrid = getAttributeId(attr);
340
341     if (!attrid)
342         return false;
343
344     return deleteAttribute(attrid);
345 }
346
347 bool
348 gss_eap_radius_attr_provider::getAttribute(const gss_buffer_t attr,
349                                            int *authenticated,
350                                            int *complete,
351                                            gss_buffer_t value,
352                                            gss_buffer_t display_value,
353                                            int *more) const
354 {
355     uint32_t attrid;
356
357     attrid = getAttributeId(attr);
358     if (!attrid)
359         return false;
360
361     return getAttribute(attrid, authenticated, complete,
362                         value, display_value, more);
363 }
364
365 bool
366 gss_eap_radius_attr_provider::getAttribute(uint32_t attrid,
367                                            int *authenticated,
368                                            int *complete,
369                                            gss_buffer_t value,
370                                            gss_buffer_t display_value,
371                                            int *more) const
372 {
373     VALUE_PAIR *vp;
374     int i = *more, count = 0;
375
376     *more = 0;
377
378     if (i == -1)
379         i = 0;
380
381     if (isSecretAttributeP(attrid) || isInternalAttributeP(attrid)) {
382         return false;
383     } else if (isFragmentedAttributeP(attrid)) {
384         return getFragmentedAttribute(attrid,
385                                       authenticated,
386                                       complete,
387                                       value);
388     }
389
390     for (vp = pairfind(m_vps, attrid);
391          vp != NULL;
392          vp = pairfind(vp->next, attrid)) {
393         if (count++ == i) {
394             if (pairfind(vp->next, attrid) != NULL)
395                 *more = count;
396             break;
397         }
398     }
399
400     if (vp == NULL && *more == 0)
401         return false;
402
403     if (value != GSS_C_NO_BUFFER) {
404         gss_buffer_desc valueBuf;
405
406         valueBuf.value = (void *)vp->vp_octets;
407         valueBuf.length = vp->length;
408
409         duplicateBuffer(valueBuf, value);
410     }
411
412     if (display_value != GSS_C_NO_BUFFER &&
413         vp->type != PW_TYPE_OCTETS) {
414         char displayString[MAX_STRING_LEN];
415         gss_buffer_desc displayBuf;
416
417         displayBuf.length = vp_prints_value(displayString,
418                                             sizeof(displayString), vp, 0);
419         displayBuf.value = (void *)displayString;
420
421         duplicateBuffer(displayBuf, display_value);
422     }
423
424     if (authenticated != NULL)
425         *authenticated = m_authenticated;
426     if (complete != NULL)
427         *complete = true;
428
429     return true;
430 }
431
432 bool
433 gss_eap_radius_attr_provider::getFragmentedAttribute(uint16_t attribute,
434                                                      uint16_t vendor,
435                                                      int *authenticated,
436                                                      int *complete,
437                                                      gss_buffer_t value) const
438 {
439     OM_uint32 major, minor;
440
441     major = gssEapRadiusGetAvp(&minor, m_vps, attribute, vendor, value, TRUE);
442
443     if (authenticated != NULL)
444         *authenticated = m_authenticated;
445     if (complete != NULL)
446         *complete = true;
447
448     return !GSS_ERROR(major);
449 }
450
451 bool
452 gss_eap_radius_attr_provider::getFragmentedAttribute(uint32_t attrid,
453                                                      int *authenticated,
454                                                      int *complete,
455                                                      gss_buffer_t value) const
456 {
457     return getFragmentedAttribute(ATTRID(attrid), VENDOR(attrid),
458                                   authenticated, complete, value);
459 }
460
461 bool
462 gss_eap_radius_attr_provider::getAttribute(uint16_t attribute,
463                                            uint16_t vendor,
464                                            int *authenticated,
465                                            int *complete,
466                                            gss_buffer_t value,
467                                            gss_buffer_t display_value,
468                                            int *more) const
469 {
470
471     return getAttribute(VENDORATTR(attribute, vendor),
472                         authenticated, complete,
473                         value, display_value, more);
474 }
475
476 gss_any_t
477 gss_eap_radius_attr_provider::mapToAny(int authenticated,
478                                        gss_buffer_t type_id GSSEAP_UNUSED) const
479 {
480     if (authenticated && !m_authenticated)
481         return (gss_any_t)NULL;
482
483     return (gss_any_t)copyAvps(m_vps);
484 }
485
486 void
487 gss_eap_radius_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
488                                                     gss_any_t input) const
489 {
490     VALUE_PAIR *vp = (VALUE_PAIR *)input;
491     pairfree(&vp);
492 }
493
494 bool
495 gss_eap_radius_attr_provider::init(void)
496 {
497     gss_eap_attr_ctx::registerProvider(ATTR_TYPE_RADIUS, createAttrContext);
498
499     return true;
500 }
501
502 void
503 gss_eap_radius_attr_provider::finalize(void)
504 {
505     gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_RADIUS);
506 }
507
508 gss_eap_attr_provider *
509 gss_eap_radius_attr_provider::createAttrContext(void)
510 {
511     return new gss_eap_radius_attr_provider;
512 }
513
514 OM_uint32
515 gssEapRadiusAddAvp(OM_uint32 *minor,
516                    VALUE_PAIR **vps,
517                    uint16_t attribute,
518                    uint16_t vendor,
519                    const gss_buffer_t buffer)
520 {
521     uint32_t attrid = VENDORATTR(vendor, attribute);
522     unsigned char *p = (unsigned char *)buffer->value;
523     size_t remain = buffer->length;
524
525     do {
526         VALUE_PAIR *vp;
527         size_t n = remain;
528
529         /*
530          * There's an extra byte of padding; RADIUS AVPs can only
531          * be 253 octets.
532          */
533         if (n >= MAX_STRING_LEN)
534             n = MAX_STRING_LEN - 1;
535
536         vp = paircreate(attrid, PW_TYPE_OCTETS);
537         if (vp == NULL) {
538             *minor = ENOMEM;
539             return GSS_S_FAILURE;
540         }
541
542         memcpy(vp->vp_octets, p, n);
543         vp->length = n;
544
545         pairadd(vps, vp);
546
547         p += n;
548         remain -= n;
549     } while (remain != 0);
550
551     return GSS_S_COMPLETE;
552 }
553
554 OM_uint32
555 gssEapRadiusGetRawAvp(OM_uint32 *minor,
556                       VALUE_PAIR *vps,
557                       uint16_t attribute,
558                       uint16_t vendor,
559                       VALUE_PAIR **vp)
560 {
561     uint32_t attr = VENDORATTR(vendor, attribute);
562
563     *vp = pairfind(vps, attr);
564     if (*vp == NULL) {
565         *minor = GSSEAP_NO_SUCH_ATTR;
566         return GSS_S_UNAVAILABLE;
567     }
568
569     return GSS_S_COMPLETE;
570 }
571
572 OM_uint32
573 gssEapRadiusGetAvp(OM_uint32 *minor,
574                    VALUE_PAIR *vps,
575                    uint16_t attribute,
576                    uint16_t vendor,
577                    gss_buffer_t buffer,
578                    int concat)
579 {
580     VALUE_PAIR *vp;
581     unsigned char *p;
582     uint32_t attr = VENDORATTR(vendor, attribute);
583
584     if (buffer != GSS_C_NO_BUFFER) {
585         buffer->length = 0;
586         buffer->value = NULL;
587     }
588
589     vp = pairfind(vps, attr);
590     if (vp == NULL) {
591         *minor = GSSEAP_NO_SUCH_ATTR;
592         return GSS_S_UNAVAILABLE;
593     }
594
595     if (buffer != GSS_C_NO_BUFFER) {
596         do {
597             buffer->length += vp->length;
598         } while (concat && (vp = pairfind(vp->next, attr)) != NULL);
599
600         buffer->value = GSSEAP_MALLOC(buffer->length);
601         if (buffer->value == NULL) {
602             *minor = ENOMEM;
603             return GSS_S_FAILURE;
604         }
605
606         p = (unsigned char *)buffer->value;
607
608         for (vp = pairfind(vps, attr);
609              concat && vp != NULL;
610              vp = pairfind(vp->next, attr)) {
611             memcpy(p, vp->vp_octets, vp->length);
612             p += vp->length;
613         }
614     }
615
616     *minor = 0;
617     return GSS_S_COMPLETE;
618 }
619
620 OM_uint32
621 gssEapRadiusFreeAvps(OM_uint32 *minor,
622                      VALUE_PAIR **vps)
623 {
624     pairfree(vps);
625     *minor = 0;
626     return GSS_S_COMPLETE;
627 }
628
629 OM_uint32
630 gssEapRadiusAttrProviderInit(OM_uint32 *minor)
631 {
632     if (!gss_eap_radius_attr_provider::init()) {
633         *minor = GSSEAP_RADSEC_INIT_FAILURE;
634         return GSS_S_FAILURE;
635     }
636
637     return GSS_S_COMPLETE;
638 }
639
640 OM_uint32
641 gssEapRadiusAttrProviderFinalize(OM_uint32 *minor)
642 {
643     gss_eap_radius_attr_provider::finalize();
644
645     *minor = 0;
646     return GSS_S_COMPLETE;
647 }
648
649 static JSONObject
650 avpToJson(const VALUE_PAIR *vp)
651 {
652     JSONObject obj;
653
654     GSSEAP_ASSERT(vp->length <= MAX_STRING_LEN);
655
656     switch (vp->type) {
657     case PW_TYPE_INTEGER:
658     case PW_TYPE_IPADDR:
659     case PW_TYPE_DATE:
660         obj.set("value", vp->lvalue);
661         break;
662     case PW_TYPE_STRING:
663         obj.set("value", vp->vp_strvalue);
664         break;
665     default: {
666         char *b64;
667
668         if (base64Encode(vp->vp_octets, vp->length, &b64) < 0)
669             throw std::bad_alloc();
670
671         obj.set("value", b64);
672         GSSEAP_FREE(b64);
673         break;
674     }
675     }
676
677     obj.set("type", vp->attribute);
678
679     return obj;
680 }
681
682 static bool
683 jsonToAvp(VALUE_PAIR **pVp, JSONObject &obj)
684 {
685     VALUE_PAIR *vp = NULL;
686     DICT_ATTR *da;
687     uint32_t attrid;
688
689     JSONObject type = obj["type"];
690     JSONObject value = obj["value"];
691
692     if (!type.isInteger())
693         goto fail;
694
695     attrid = type.integer();
696     da = dict_attrbyvalue(attrid);
697     if (da != NULL) {
698         vp = pairalloc(da);
699     } else {
700         int type = base64Valid(value.string()) ?
701             PW_TYPE_OCTETS : PW_TYPE_STRING;
702         vp = paircreate(attrid, type);
703     }
704     if (vp == NULL)
705         throw std::bad_alloc();
706
707     switch (vp->type) {
708     case PW_TYPE_INTEGER:
709     case PW_TYPE_IPADDR:
710     case PW_TYPE_DATE:
711         if (!value.isInteger())
712             goto fail;
713
714         vp->length = 4;
715         vp->lvalue = value.integer();
716         break;
717     case PW_TYPE_STRING: {
718         if (!value.isString())
719             goto fail;
720
721         const char *str = value.string();
722         size_t len = strlen(str);
723
724         if (len >= MAX_STRING_LEN)
725             goto fail;
726
727         vp->length = len;
728         memcpy(vp->vp_strvalue, str, len + 1);
729         break;
730     }
731     case PW_TYPE_OCTETS:
732     default: {
733         if (!value.isString())
734             goto fail;
735
736         const char *str = value.string();
737         ssize_t len = strlen(str);
738
739         /* this optimization requires base64Decode only understand packed encoding */
740         if (len >= BASE64_EXPAND(MAX_STRING_LEN))
741             goto fail;
742
743         len = base64Decode(str, vp->vp_octets);
744         if (len < 0)
745             goto fail;
746
747         vp->length = len;
748         break;
749     }
750     }
751
752     *pVp = vp;
753
754     return true;
755
756 fail:
757     if (vp != NULL)
758         pairbasicfree(vp);
759     *pVp = NULL;
760     return false;
761 }
762
763 const char *
764 gss_eap_radius_attr_provider::name(void) const
765 {
766     return "radius";
767 }
768
769 bool
770 gss_eap_radius_attr_provider::initWithJsonObject(const gss_eap_attr_ctx *ctx,
771                                                  JSONObject &obj)
772 {
773     VALUE_PAIR **pNext = &m_vps;
774
775     if (!gss_eap_attr_provider::initWithJsonObject(ctx, obj))
776         return false;
777
778     JSONObject attrs = obj["attributes"];
779     size_t nelems = attrs.size();
780
781     for (size_t i = 0; i < nelems; i++) {
782         JSONObject attr = attrs[i];
783         VALUE_PAIR *vp;
784
785         if (!jsonToAvp(&vp, attr))
786             return false;
787
788         *pNext = vp;
789         pNext = &vp->next;
790     }
791
792     m_authenticated = obj["authenticated"].integer() ? true : false;
793
794     return true;
795 }
796
797 const char *
798 gss_eap_radius_attr_provider::prefix(void) const
799 {
800     return "urn:ietf:params:gss-eap:radius-avp";
801 }
802
803 JSONObject
804 gss_eap_radius_attr_provider::jsonRepresentation(void) const
805 {
806     JSONObject obj, attrs = JSONObject::array();
807
808     for (VALUE_PAIR *vp = m_vps; vp != NULL; vp = vp->next) {
809         JSONObject attr = avpToJson(vp);
810         attrs.append(attr);
811     }
812
813     obj.set("attributes", attrs);
814
815     obj.set("authenticated", m_authenticated);
816
817     return obj;
818 }
819
820 time_t
821 gss_eap_radius_attr_provider::getExpiryTime(void) const
822 {
823     VALUE_PAIR *vp;
824
825     vp = pairfind(m_vps, PW_SESSION_TIMEOUT);
826     if (vp == NULL || vp->lvalue == 0)
827         return 0;
828
829     return time(NULL) + vp->lvalue;
830 }
831
832 OM_uint32
833 gssEapRadiusMapError(OM_uint32 *minor,
834                      struct rs_error *err)
835 {
836     int code;
837
838     GSSEAP_ASSERT(err != NULL);
839
840     code = rs_err_code(err, 0);
841
842     if (code == RSE_OK) {
843         *minor = 0;
844         return GSS_S_COMPLETE;
845     }
846
847     *minor = ERROR_TABLE_BASE_rse + code;
848
849     gssEapSaveStatusInfo(*minor, "%s", rs_err_msg(err));
850     rs_err_free(err);
851
852     return GSS_S_FAILURE;
853 }
854
855 OM_uint32
856 gssEapCreateRadiusContext(OM_uint32 *minor,
857                           gss_cred_id_t cred,
858                           struct rs_context **pRadContext)
859 {
860     const char *configFile = RS_CONFIG_FILE;
861     struct rs_context *radContext;
862     struct rs_alloc_scheme ralloc;
863     struct rs_error *err;
864     OM_uint32 major;
865
866     *pRadContext = NULL;
867
868     if (rs_context_create(&radContext) != 0) {
869         *minor = GSSEAP_RADSEC_CONTEXT_FAILURE;
870         return GSS_S_FAILURE;
871     }
872
873     if (cred->radiusConfigFile.value != NULL)
874         configFile = (const char *)cred->radiusConfigFile.value;
875
876     ralloc.calloc  = GSSEAP_CALLOC;
877     ralloc.malloc  = GSSEAP_MALLOC;
878     ralloc.free    = GSSEAP_FREE;
879     ralloc.realloc = GSSEAP_REALLOC;
880
881     rs_context_set_alloc_scheme(radContext, &ralloc);
882
883     if (rs_context_read_config(radContext, configFile) != 0) {
884         err = rs_err_ctx_pop(radContext);
885         goto fail;
886     }
887
888     if (rs_context_init_freeradius_dict(radContext, NULL) != 0) {
889         err = rs_err_ctx_pop(radContext);
890         goto fail;
891     }
892
893     *pRadContext = radContext;
894
895     *minor = 0;
896     return GSS_S_COMPLETE;
897
898 fail:
899     major = gssEapRadiusMapError(minor, err);
900     rs_context_destroy(radContext);
901
902     return major;
903 }
904
905 #endif /* GSSEAP_ENABLE_ACCEPTOR */
906
907 OM_uint32
908 gssEapRadiusAddAttr(OM_uint32 *minor, struct wpabuf **buf, uint16_t attr,
909                     uint16_t vendor, gss_buffer_t buffer)
910 {
911     if (radius_add_tlv(buf, attr, vendor, (u8 *)buffer->value,
912                        buffer->length) < 0) {
913         *minor = ENOMEM; /* could be length too long, though */
914         return GSS_S_FAILURE;
915     }
916     return GSS_S_COMPLETE;
917 }