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