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