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