plug a leak
[mech_eap.orig] / util_attr.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 #include <typeinfo>
36 #include <string>
37 #include <exception>
38 #include <new>
39
40 /* lazy initialisation */
41 static GSSEAP_THREAD_ONCE gssEapAttrProvidersInitOnce = GSSEAP_ONCE_INITIALIZER;
42 static OM_uint32 gssEapAttrProvidersInitStatus = GSS_S_UNAVAILABLE;
43
44 static void
45 gssEapAttrProvidersInitInternal(void)
46 {
47     OM_uint32 major, minor;
48
49     major = gssEapRadiusAttrProviderInit(&minor);
50     assert(major == GSS_S_COMPLETE);
51
52     major = gssEapSamlAttrProvidersInit(&minor);
53     assert(major == GSS_S_COMPLETE);
54
55     major = gssEapLocalAttrProviderInit(&minor);
56     assert(major == GSS_S_COMPLETE);
57
58     gssEapAttrProvidersInitStatus = major;
59 }
60
61 static void
62 gssEapAttrProvidersInit(void)
63 {
64     GSSEAP_ONCE(&gssEapAttrProvidersInitOnce, gssEapAttrProvidersInitInternal);
65 }
66
67 OM_uint32
68 gssEapAttrProvidersFinalize(OM_uint32 *minor)
69 {
70     OM_uint32 major = GSS_S_COMPLETE;
71
72     if (gssEapAttrProvidersInitStatus == GSS_S_COMPLETE) {
73         major = gssEapLocalAttrProviderFinalize(minor);
74         major = gssEapSamlAttrProvidersFinalize(minor);
75         major = gssEapRadiusAttrProviderFinalize(minor);
76     }
77
78     return GSS_S_COMPLETE;
79 }
80
81 static gss_eap_attr_create_provider gssEapAttrFactories[ATTR_TYPE_MAX + 1];
82 static gss_buffer_desc gssEapAttrPrefixes[ATTR_TYPE_MAX + 1];
83
84 /*
85  * Register a provider for a particular type and prefix
86  */
87 void
88 gss_eap_attr_ctx::registerProvider(unsigned int type,
89                                    const char *prefix,
90                                    gss_eap_attr_create_provider factory)
91 {
92     assert(type <= ATTR_TYPE_MAX);
93
94     assert(gssEapAttrFactories[type] == NULL);
95
96     gssEapAttrFactories[type] = factory;
97     if (prefix != NULL) {
98         gssEapAttrPrefixes[type].value = (void *)prefix;
99         gssEapAttrPrefixes[type].length = strlen(prefix);
100     } else {
101         gssEapAttrPrefixes[type].value = NULL;
102         gssEapAttrPrefixes[type].length = 0;
103     }
104 }
105
106 /*
107  * Unregister a provider
108  */
109 void
110 gss_eap_attr_ctx::unregisterProvider(unsigned int type)
111 {
112     assert(type <= ATTR_TYPE_MAX);
113
114     gssEapAttrFactories[type] = NULL;
115     gssEapAttrPrefixes[type].value = NULL;
116     gssEapAttrPrefixes[type].length = 0;
117 }
118
119 /*
120  * Create an attribute context, that manages instances of providers
121  */
122 gss_eap_attr_ctx::gss_eap_attr_ctx(void)
123 {
124     m_flags = 0;
125
126     for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
127         gss_eap_attr_provider *provider;
128
129         if (gssEapAttrFactories[i] != NULL) {
130             provider = (gssEapAttrFactories[i])();
131         } else {
132             provider = NULL;
133         }
134
135         m_providers[i] = provider;
136     }
137 }
138
139 /*
140  * Convert an attribute prefix to a type
141  */
142 unsigned int
143 gss_eap_attr_ctx::attributePrefixToType(const gss_buffer_t prefix)
144 {
145     unsigned int i;
146
147     for (i = ATTR_TYPE_MIN; i < ATTR_TYPE_MAX; i++) {
148         if (bufferEqual(&gssEapAttrPrefixes[i], prefix))
149             return i;
150     }
151
152     return ATTR_TYPE_LOCAL;
153 }
154
155 /*
156  * Convert a type to an attribute prefix
157  */
158 const gss_buffer_t
159 gss_eap_attr_ctx::attributeTypeToPrefix(unsigned int type)
160 {
161     if (type < ATTR_TYPE_MIN || type >= ATTR_TYPE_MAX)
162         return GSS_C_NO_BUFFER;
163
164     return &gssEapAttrPrefixes[type];
165 }
166
167 bool
168 gss_eap_attr_ctx::providerEnabled(unsigned int type) const
169 {
170     if (type == ATTR_TYPE_LOCAL &&
171         (m_flags & ATTR_FLAG_DISABLE_LOCAL))
172         return false;
173
174     if (m_providers[type] == NULL)
175         return false;
176
177     return true;
178 }
179
180 void
181 gss_eap_attr_ctx::releaseProvider(unsigned int type)
182 {
183     delete m_providers[type];
184     m_providers[type] = NULL;
185 }
186
187 /*
188  * Initialize a context from an existing context.
189  */
190 bool
191 gss_eap_attr_ctx::initFromExistingContext(const gss_eap_attr_ctx *manager)
192 {
193     bool ret = true;
194
195     m_flags = manager->m_flags;
196
197     for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
198         gss_eap_attr_provider *provider;
199
200         if (!providerEnabled(i)) {
201             releaseProvider(i);
202             continue;
203         }
204
205         provider = m_providers[i];
206
207         ret = provider->initFromExistingContext(this,
208                                                 manager->m_providers[i]);
209         if (ret == false) {
210             releaseProvider(i);
211             break;
212         }
213     }
214
215     return ret;
216 }
217
218 /*
219  * Initialize a context from a GSS credential and context.
220  */
221 bool
222 gss_eap_attr_ctx::initFromGssContext(const gss_cred_id_t cred,
223                                      const gss_ctx_id_t ctx)
224 {
225     bool ret = true;
226
227     if (cred != GSS_C_NO_CREDENTIAL &&
228         (cred->flags & GSS_EAP_DISABLE_LOCAL_ATTRS_FLAG)) {
229         m_flags |= ATTR_FLAG_DISABLE_LOCAL;
230     }
231
232     for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
233         gss_eap_attr_provider *provider;
234
235         if (!providerEnabled(i)) {
236             releaseProvider(i);
237             continue;
238         }
239
240         provider = m_providers[i];
241
242         ret = provider->initFromGssContext(this, cred, ctx);
243         if (ret == false) {
244             releaseProvider(i);
245             break;
246         }
247     }
248
249     return ret;
250 }
251
252 /*
253  * Initialize a context from an exported context or name token
254  */
255 bool
256 gss_eap_attr_ctx::initFromBuffer(const gss_buffer_t buffer)
257 {
258     bool ret;
259     gss_eap_attr_provider *primaryProvider = getPrimaryProvider();
260     gss_buffer_desc primaryBuf;
261
262     if (buffer->length < 4)
263         return false;
264
265     m_flags = load_uint32_be(buffer->value);
266
267     primaryBuf.length = buffer->length - 4;
268     primaryBuf.value = (char *)buffer->value + 4;
269
270     ret = primaryProvider->initFromBuffer(this, &primaryBuf);
271     if (ret == false)
272         return ret;
273
274     for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
275         gss_eap_attr_provider *provider;
276
277         if (!providerEnabled(i)) {
278             releaseProvider(i);
279             continue;
280         }
281
282         provider = m_providers[i];
283         if (provider == primaryProvider)
284             continue;
285
286         ret = provider->initFromGssContext(this,
287                                            GSS_C_NO_CREDENTIAL,
288                                            GSS_C_NO_CONTEXT);
289         if (ret == false) {
290             releaseProvider(i);
291             break;
292         }
293     }
294
295     return ret;
296 }
297
298 gss_eap_attr_ctx::~gss_eap_attr_ctx(void)
299 {
300     for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++)
301         delete m_providers[i];
302 }
303
304 /*
305  * Locate provider for a given type
306  */
307 gss_eap_attr_provider *
308 gss_eap_attr_ctx::getProvider(unsigned int type) const
309 {
310     assert(type >= ATTR_TYPE_MIN && type <= ATTR_TYPE_MAX);
311     return m_providers[type];
312 }
313
314 /*
315  * Locate provider for a given prefix
316  */
317 gss_eap_attr_provider *
318 gss_eap_attr_ctx::getProvider(const gss_buffer_t prefix) const
319 {
320     unsigned int type;
321
322     type = attributePrefixToType(prefix);
323
324     return m_providers[type];
325 }
326
327 /*
328  * Get primary provider. Only the primary provider is serialised when
329  * gss_export_sec_context() or gss_export_name_composite() is called.
330  */
331 gss_eap_attr_provider *
332 gss_eap_attr_ctx::getPrimaryProvider(void) const
333 {
334     return m_providers[ATTR_TYPE_MIN];
335 }
336
337 /*
338  * Set an attribute
339  */
340 void
341 gss_eap_attr_ctx::setAttribute(int complete,
342                                const gss_buffer_t attr,
343                                const gss_buffer_t value)
344 {
345     gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
346     unsigned int type;
347     gss_eap_attr_provider *provider;
348
349     decomposeAttributeName(attr, &type, &suffix);
350
351     provider = m_providers[type];
352     if (provider != NULL) {
353         provider->setAttribute(complete,
354                                (type == ATTR_TYPE_LOCAL) ? attr : &suffix,
355                                value);
356     } else {
357         /* XXX TODO throw exception */
358     }
359 }
360
361 /*
362  * Delete an attrbiute
363  */
364 void
365 gss_eap_attr_ctx::deleteAttribute(const gss_buffer_t attr)
366 {
367     gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
368     unsigned int type;
369     gss_eap_attr_provider *provider;
370
371     decomposeAttributeName(attr, &type, &suffix);
372
373     provider = m_providers[type];
374     if (provider != NULL)
375         provider->deleteAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix);
376 }
377
378 /*
379  * Enumerate attribute types with callback
380  */
381 bool
382 gss_eap_attr_ctx::getAttributeTypes(gss_eap_attr_enumeration_cb cb, void *data) const
383 {
384     bool ret = false;
385     size_t i;
386
387     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
388         gss_eap_attr_provider *provider = m_providers[i];
389
390         if (provider == NULL)
391             continue;
392
393         ret = provider->getAttributeTypes(cb, data);
394         if (ret == false)
395             break;
396     }
397
398     return ret;
399 }
400
401 struct eap_gss_get_attr_types_args {
402     unsigned int type;
403     gss_buffer_set_t attrs;
404 };
405
406 static bool
407 addAttribute(const gss_eap_attr_provider *provider,
408              const gss_buffer_t attribute,
409              void *data)
410 {
411     eap_gss_get_attr_types_args *args = (eap_gss_get_attr_types_args *)data;
412     gss_buffer_desc qualified;
413     OM_uint32 major, minor;
414
415     if (args->type != ATTR_TYPE_LOCAL) {
416         gss_eap_attr_ctx::composeAttributeName(args->type, attribute, &qualified);
417         major = gss_add_buffer_set_member(&minor, &qualified, &args->attrs);
418         gss_release_buffer(&minor, &qualified);
419     } else {
420         major = gss_add_buffer_set_member(&minor, attribute, &args->attrs);
421     }
422
423     return GSS_ERROR(major) == false;
424 }
425
426 /*
427  * Enumerate attribute types, output is buffer set
428  */
429 bool
430 gss_eap_attr_ctx::getAttributeTypes(gss_buffer_set_t *attrs)
431 {
432     eap_gss_get_attr_types_args args;
433     OM_uint32 major, minor;
434     bool ret = false;
435     unsigned int i;
436
437     major = gss_create_empty_buffer_set(&minor, attrs);
438     if (GSS_ERROR(major)) {
439         throw new std::bad_alloc;
440         return false;
441     }
442
443     args.attrs = *attrs;
444
445     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
446         gss_eap_attr_provider *provider = m_providers[i];
447
448         args.type = i;
449
450         if (provider == NULL)
451             continue;
452
453         ret = provider->getAttributeTypes(addAttribute, (void *)&args);
454         if (ret == false)
455             break;
456     }
457
458     if (ret == false)
459         gss_release_buffer_set(&minor, attrs);
460
461     return ret;
462 }
463
464 /*
465  * Get attribute with given name
466  */
467 bool
468 gss_eap_attr_ctx::getAttribute(const gss_buffer_t attr,
469                                int *authenticated,
470                                int *complete,
471                                gss_buffer_t value,
472                                gss_buffer_t display_value,
473                                int *more) const
474 {
475     gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
476     unsigned int type;
477     gss_eap_attr_provider *provider;
478     bool ret;
479
480     decomposeAttributeName(attr, &type, &suffix);
481
482     provider = m_providers[type];
483     if (provider == NULL)
484         return false;
485
486     ret = provider->getAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix,
487                                  authenticated, complete,
488                                  value, display_value, more);
489
490     return ret;
491 }
492
493 /*
494  * Map attribute context to C++ object
495  */
496 gss_any_t
497 gss_eap_attr_ctx::mapToAny(int authenticated,
498                            gss_buffer_t type_id) const
499 {
500     unsigned int type;
501     gss_eap_attr_provider *provider;
502     gss_buffer_desc suffix;
503
504     decomposeAttributeName(type_id, &type, &suffix);
505
506     provider = m_providers[type];
507     if (provider == NULL)
508         return (gss_any_t)NULL;
509
510     return provider->mapToAny(authenticated, &suffix);
511 }
512
513 /*
514  * Release mapped context
515  */
516 void
517 gss_eap_attr_ctx::releaseAnyNameMapping(gss_buffer_t type_id,
518                                         gss_any_t input) const
519 {
520     unsigned int type;
521     gss_eap_attr_provider *provider;
522     gss_buffer_desc suffix;
523
524     decomposeAttributeName(type_id, &type, &suffix);
525
526     provider = m_providers[type];
527     if (provider != NULL)
528         provider->releaseAnyNameMapping(&suffix, input);
529 }
530
531 /*
532  * Export attribute context to buffer
533  */
534 void
535 gss_eap_attr_ctx::exportToBuffer(gss_buffer_t buffer) const
536 {
537     const gss_eap_attr_provider *primaryProvider = getPrimaryProvider();
538     gss_buffer_desc tmp;
539     unsigned char *p;
540     OM_uint32 tmpMinor;
541
542     primaryProvider->exportToBuffer(&tmp);
543
544     buffer->length = 4 + tmp.length;
545     buffer->value = GSSEAP_MALLOC(buffer->length);
546     if (buffer->value == NULL)
547         throw new std::bad_alloc;
548
549     p = (unsigned char *)buffer->value;
550     store_uint32_be(m_flags, p);
551     memcpy(p + 4, tmp.value, tmp.length);
552
553     gss_release_buffer(&tmpMinor, &tmp);
554 }
555
556 /*
557  * Return soonest expiry time of providers
558  */
559 time_t
560 gss_eap_attr_ctx::getExpiryTime(void) const
561 {
562     unsigned int i;
563     time_t expiryTime = 0;
564
565     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
566         gss_eap_attr_provider *provider = m_providers[i];
567         time_t providerExpiryTime;
568
569         if (provider == NULL)
570             continue;
571
572         providerExpiryTime = provider->getExpiryTime();
573         if (providerExpiryTime == 0)
574             continue;
575
576         if (expiryTime == 0 || providerExpiryTime < expiryTime)
577             expiryTime = providerExpiryTime;
578     }
579
580     return expiryTime;
581 }
582
583 /*
584  * Map C++ exception to GSS status
585  */
586 static OM_uint32
587 mapException(OM_uint32 *minor, std::exception &e)
588 {
589     OM_uint32 major = GSS_S_FAILURE;
590
591     /* XXX TODO implement other mappings */
592     if (typeid(e) == typeid(std::bad_alloc))
593         *minor = ENOMEM;
594     else
595         *minor = 0;
596
597 #ifdef GSSEAP_DEBUG
598     /* rethrow for now for debugging */
599     throw e;
600 #endif
601
602     return major;
603 }
604
605 /*
606  * Decompose attribute name into prefix and suffix
607  */
608 void
609 gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
610                                          gss_buffer_t prefix,
611                                          gss_buffer_t suffix)
612 {
613     char *p = NULL;
614     size_t i;
615
616     for (i = 0; i < attribute->length; i++) {
617         if (((char *)attribute->value)[i] == ' ') {
618             p = (char *)attribute->value + i + 1;
619             break;
620         }
621     }
622
623     prefix->value = attribute->value;
624     prefix->length = i;
625
626     if (p != NULL && *p != '\0')  {
627         suffix->length = attribute->length - 1 - prefix->length;
628         suffix->value = p;
629     } else {
630         suffix->length = 0;
631         suffix->value = NULL;
632     }
633 }
634
635 /*
636  * Decompose attribute name into type and suffix
637  */
638 void
639 gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
640                                          unsigned int *type,
641                                          gss_buffer_t suffix)
642 {
643     gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
644
645     decomposeAttributeName(attribute, &prefix, suffix);
646     *type = attributePrefixToType(&prefix);
647 }
648
649 /*
650  * Compose attribute name from prefix, suffix; returns C++ string
651  */
652 std::string
653 gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
654                                        const gss_buffer_t suffix)
655 {
656     std::string str;
657
658     if (prefix == GSS_C_NO_BUFFER || prefix->length == 0)
659         return str;
660
661     str.append((const char *)prefix->value, prefix->length);
662
663     if (suffix != GSS_C_NO_BUFFER) {
664         str.append(" ");
665         str.append((const char *)suffix->value, suffix->length);
666     }
667
668     return str;
669 }
670
671 /*
672  * Compose attribute name from type, suffix; returns C++ string
673  */
674 std::string
675 gss_eap_attr_ctx::composeAttributeName(unsigned int type,
676                                        const gss_buffer_t suffix)
677 {
678     const gss_buffer_t prefix = attributeTypeToPrefix(type);
679
680     return composeAttributeName(prefix, suffix);
681 }
682
683 /*
684  * Compose attribute name from prefix, suffix; returns GSS buffer
685  */
686 void
687 gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
688                                        const gss_buffer_t suffix,
689                                        gss_buffer_t attribute)
690 {
691     std::string str = composeAttributeName(prefix, suffix);
692
693     if (str.length() != 0) {
694         return duplicateBuffer(str, attribute);
695     } else {
696         attribute->length = 0;
697         attribute->value = NULL;
698     }
699 }
700
701 /*
702  * Compose attribute name from type, suffix; returns GSS buffer
703  */
704 void
705 gss_eap_attr_ctx::composeAttributeName(unsigned int type,
706                                        const gss_buffer_t suffix,
707                                        gss_buffer_t attribute)
708 {
709     gss_buffer_t prefix = attributeTypeToPrefix(type);
710
711     return composeAttributeName(prefix, suffix, attribute);
712 }
713
714 /*
715  * C wrappers
716  */
717 OM_uint32
718 gssEapInquireName(OM_uint32 *minor,
719                   gss_name_t name,
720                   int *name_is_MN,
721                   gss_OID *MN_mech,
722                   gss_buffer_set_t *attrs)
723 {
724     if (name->attrCtx == NULL)
725         return GSS_S_UNAVAILABLE;
726
727     gssEapAttrProvidersInit();
728
729     try {
730         if (!name->attrCtx->getAttributeTypes(attrs))
731             return GSS_S_UNAVAILABLE;
732     } catch (std::exception &e) {
733         return mapException(minor, e);
734     }
735
736     return GSS_S_COMPLETE;
737 }
738
739 OM_uint32
740 gssEapGetNameAttribute(OM_uint32 *minor,
741                        gss_name_t name,
742                        gss_buffer_t attr,
743                        int *authenticated,
744                        int *complete,
745                        gss_buffer_t value,
746                        gss_buffer_t display_value,
747                        int *more)
748 {
749     *authenticated = 0;
750     *complete = 0;
751
752     if (value != NULL) {
753         value->length = 0;
754         value->value = NULL;
755     }
756
757     if (display_value != NULL) {
758         display_value->length = 0;
759         display_value->value = NULL;
760     }
761
762     if (name->attrCtx == NULL)
763         return GSS_S_UNAVAILABLE;
764
765     gssEapAttrProvidersInit();
766
767     try {
768         if (!name->attrCtx->getAttribute(attr, authenticated, complete,
769                                          value, display_value, more))
770             return GSS_S_UNAVAILABLE;
771     } catch (std::exception &e) {
772         return mapException(minor, e);
773     }
774
775     return GSS_S_COMPLETE;
776 }
777
778 OM_uint32
779 gssEapDeleteNameAttribute(OM_uint32 *minor,
780                           gss_name_t name,
781                           gss_buffer_t attr)
782 {
783     if (name->attrCtx == NULL)
784         return GSS_S_UNAVAILABLE;
785
786     gssEapAttrProvidersInit();
787
788     try {
789         name->attrCtx->deleteAttribute(attr);
790     } catch (std::exception &ex) {
791         return mapException(minor, ex);
792     }
793
794     return GSS_S_COMPLETE;
795 }
796
797 OM_uint32
798 gssEapSetNameAttribute(OM_uint32 *minor,
799                        gss_name_t name,
800                        int complete,
801                        gss_buffer_t attr,
802                        gss_buffer_t value)
803 {
804     if (name->attrCtx == NULL)
805         return GSS_S_UNAVAILABLE;
806
807     gssEapAttrProvidersInit();
808
809     try {
810         name->attrCtx->setAttribute(complete, attr, value);
811     } catch (std::exception &ex) {
812         return mapException(minor, ex);
813     }
814
815     return GSS_S_COMPLETE;
816 }
817
818 OM_uint32
819 gssEapExportAttrContext(OM_uint32 *minor,
820                         gss_name_t name,
821                         gss_buffer_t buffer)
822 {
823     if (name->attrCtx == NULL) {
824         buffer->length = 0;
825         buffer->value = NULL;
826
827         return GSS_S_COMPLETE;
828     }
829
830     gssEapAttrProvidersInit();
831
832     try {
833         name->attrCtx->exportToBuffer(buffer);
834     } catch (std::exception &e) {
835         return mapException(minor, e);
836     }
837
838     return GSS_S_COMPLETE;
839 }
840
841 OM_uint32
842 gssEapImportAttrContext(OM_uint32 *minor,
843                         gss_buffer_t buffer,
844                         gss_name_t name)
845 {
846     gss_eap_attr_ctx *ctx = NULL;
847
848     assert(name->attrCtx == NULL);
849
850     gssEapAttrProvidersInit();
851
852     if (buffer->length != 0) {
853         try {
854             ctx = new gss_eap_attr_ctx();
855
856             if (!ctx->initFromBuffer(buffer)) {
857                 delete ctx;
858                 return GSS_S_DEFECTIVE_TOKEN;
859             }
860             name->attrCtx = ctx;
861         } catch (std::exception &e) {
862             delete ctx;
863             return mapException(minor, e);
864         }
865     }
866
867     return GSS_S_COMPLETE;
868 }
869
870 OM_uint32
871 gssEapDuplicateAttrContext(OM_uint32 *minor,
872                            gss_name_t in,
873                            gss_name_t out)
874 {
875     gss_eap_attr_ctx *ctx = NULL;
876
877     assert(out->attrCtx == NULL);
878
879     gssEapAttrProvidersInit();
880
881     try {
882         if (in->attrCtx != NULL) {
883             ctx = new gss_eap_attr_ctx();
884             if (!ctx->initFromExistingContext(in->attrCtx)) {
885                 delete ctx;
886                 return GSS_S_FAILURE;
887             }
888             out->attrCtx = ctx;
889         }
890     } catch (std::exception &e) {
891         delete ctx;
892         return mapException(minor, e);
893     }
894
895     return GSS_S_COMPLETE;
896 }
897
898 OM_uint32
899 gssEapMapNameToAny(OM_uint32 *minor,
900                    gss_name_t name,
901                    int authenticated,
902                    gss_buffer_t type_id,
903                    gss_any_t *output)
904 {
905     if (name->attrCtx == NULL)
906         return GSS_S_UNAVAILABLE;
907
908     gssEapAttrProvidersInit();
909
910     try {
911         *output = name->attrCtx->mapToAny(authenticated, type_id);
912     } catch (std::exception &e) {
913         return mapException(minor, e);
914     }
915
916     return GSS_S_COMPLETE;
917 }
918
919 OM_uint32
920 gssEapReleaseAnyNameMapping(OM_uint32 *minor,
921                             gss_name_t name,
922                             gss_buffer_t type_id,
923                             gss_any_t *input)
924 {
925     if (name->attrCtx == NULL)
926         return GSS_S_UNAVAILABLE;
927
928     gssEapAttrProvidersInit();
929
930     try {
931         if (*input != NULL)
932             name->attrCtx->releaseAnyNameMapping(type_id, *input);
933         *input = NULL;
934     } catch (std::exception &e) {
935         return mapException(minor, e);
936     }
937
938     return GSS_S_COMPLETE;
939 }
940
941 OM_uint32
942 gssEapReleaseAttrContext(OM_uint32 *minor,
943                          gss_name_t name)
944 {
945     if (name->attrCtx != NULL)
946         delete name->attrCtx;
947
948     return GSS_S_COMPLETE;
949 }
950
951 /*
952  * Public accessor for initialisng a context from a GSS context. Also
953  * sets expiry time on GSS context as a side-effect.
954  */
955 struct gss_eap_attr_ctx *
956 gssEapCreateAttrContext(gss_cred_id_t gssCred,
957                         gss_ctx_id_t gssCtx)
958 {
959     gss_eap_attr_ctx *ctx;
960
961     assert(gssCtx != GSS_C_NO_CONTEXT);
962
963     gssEapAttrProvidersInit();
964
965     ctx = new gss_eap_attr_ctx();
966     if (!ctx->initFromGssContext(gssCred, gssCtx)) {
967         delete ctx;
968         return NULL;
969     }
970
971     gssCtx->expiryTime = ctx->getExpiryTime();
972
973     return ctx;
974 }