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