Merge remote branch 'origin/master' into HEAD
[moonshot.git] / moonshot / mech_eap / util_attr.cpp
1 /*
2  * Copyright (c) 2011, JANET(UK)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of JANET(UK) nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 /*
34  * Attribute provider mechanism.
35  */
36
37 #include "gssapiP_eap.h"
38
39 #include <typeinfo>
40 #include <string>
41 #include <sstream>
42 #include <exception>
43 #include <new>
44
45 /* lazy initialisation */
46 static GSSEAP_THREAD_ONCE gssEapAttrProvidersInitOnce = GSSEAP_ONCE_INITIALIZER;
47 static OM_uint32 gssEapAttrProvidersInitStatus = GSS_S_UNAVAILABLE;
48
49 static void
50 gssEapAttrProvidersInitInternal(void)
51 {
52     OM_uint32 major, minor;
53
54     assert(gssEapAttrProvidersInitStatus == GSS_S_UNAVAILABLE);
55
56     major = gssEapRadiusAttrProviderInit(&minor);
57     if (GSS_ERROR(major))
58         goto cleanup;
59
60     major = gssEapSamlAttrProvidersInit(&minor);
61     if (GSS_ERROR(major))
62         goto cleanup;
63
64     /* Allow Shibboleth initialization failure to be non-fatal */
65     gssEapLocalAttrProviderInit(&minor);
66
67 cleanup:
68 #ifdef GSSEAP_DEBUG
69     assert(major == GSS_S_COMPLETE);
70 #endif
71
72     gssEapAttrProvidersInitStatus = major;
73 }
74
75 static OM_uint32
76 gssEapAttrProvidersInit(OM_uint32 *minor)
77 {
78     GSSEAP_ONCE(&gssEapAttrProvidersInitOnce, gssEapAttrProvidersInitInternal);
79
80     if (GSS_ERROR(gssEapAttrProvidersInitStatus))
81         *minor = GSSEAP_NO_ATTR_PROVIDERS;
82
83     return gssEapAttrProvidersInitStatus;
84 }
85
86 OM_uint32
87 gssEapAttrProvidersFinalize(OM_uint32 *minor)
88 {
89     OM_uint32 major = GSS_S_COMPLETE;
90
91     if (gssEapAttrProvidersInitStatus == GSS_S_COMPLETE) {
92         major = gssEapLocalAttrProviderFinalize(minor);
93         if (major == GSS_S_COMPLETE)
94             major = gssEapSamlAttrProvidersFinalize(minor);
95         if (major == GSS_S_COMPLETE)
96             major = gssEapRadiusAttrProviderFinalize(minor);
97
98         gssEapAttrProvidersInitStatus = GSS_S_UNAVAILABLE;
99     }
100
101     return major;
102 }
103
104 static gss_eap_attr_create_provider gssEapAttrFactories[ATTR_TYPE_MAX + 1];
105
106 /*
107  * Register a provider for a particular type and prefix
108  */
109 void
110 gss_eap_attr_ctx::registerProvider(unsigned int type,
111                                    gss_eap_attr_create_provider factory)
112 {
113     assert(type <= ATTR_TYPE_MAX);
114
115     assert(gssEapAttrFactories[type] == NULL);
116
117     gssEapAttrFactories[type] = factory;
118 }
119
120 /*
121  * Unregister a provider
122  */
123 void
124 gss_eap_attr_ctx::unregisterProvider(unsigned int type)
125 {
126     assert(type <= ATTR_TYPE_MAX);
127
128     gssEapAttrFactories[type] = NULL;
129 }
130
131 /*
132  * Create an attribute context, that manages instances of providers
133  */
134 gss_eap_attr_ctx::gss_eap_attr_ctx(void)
135 {
136     m_flags = 0;
137
138     for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
139         gss_eap_attr_provider *provider;
140
141         if (gssEapAttrFactories[i] != NULL) {
142             provider = (gssEapAttrFactories[i])();
143         } else {
144             provider = NULL;
145         }
146
147         m_providers[i] = provider;
148     }
149 }
150
151 /*
152  * Convert an attribute prefix to a type
153  */
154 unsigned int
155 gss_eap_attr_ctx::attributePrefixToType(const gss_buffer_t prefix) const
156 {
157     unsigned int i;
158
159     for (i = ATTR_TYPE_MIN; i < ATTR_TYPE_MAX; i++) {
160         const char *pprefix;
161
162         if (!providerEnabled(i))
163             continue;
164
165         pprefix = m_providers[i]->prefix();
166         if (pprefix == NULL)
167             continue;
168
169         if (strlen(pprefix) == prefix->length &&
170             memcmp(pprefix, prefix->value, prefix->length) == 0)
171             return i;
172     }
173
174     return ATTR_TYPE_LOCAL;
175 }
176
177 /*
178  * Convert a type to an attribute prefix
179  */
180 gss_buffer_desc
181 gss_eap_attr_ctx::attributeTypeToPrefix(unsigned int type) const
182 {
183     gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
184
185     if (type < ATTR_TYPE_MIN || type >= ATTR_TYPE_MAX)
186         return prefix;
187
188     if (!providerEnabled(type))
189         return prefix;
190
191     prefix.value = (void *)m_providers[type]->prefix();
192     if (prefix.value != NULL)
193         prefix.length = strlen((char *)prefix.value);
194
195     return prefix;
196 }
197
198 bool
199 gss_eap_attr_ctx::providerEnabled(unsigned int type) const
200 {
201     if (type == ATTR_TYPE_LOCAL &&
202         (m_flags & ATTR_FLAG_DISABLE_LOCAL))
203         return false;
204
205     if (m_providers[type] == NULL)
206         return false;
207
208     return true;
209 }
210
211 void
212 gss_eap_attr_ctx::releaseProvider(unsigned int type)
213 {
214     delete m_providers[type];
215     m_providers[type] = NULL;
216 }
217
218 /*
219  * Initialize a context from an existing context.
220  */
221 bool
222 gss_eap_attr_ctx::initWithExistingContext(const gss_eap_attr_ctx *manager)
223 {
224     bool ret = true;
225
226     m_flags = manager->m_flags;
227
228     for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
229         gss_eap_attr_provider *provider;
230
231         if (!providerEnabled(i)) {
232             releaseProvider(i);
233             continue;
234         }
235
236         provider = m_providers[i];
237
238         ret = provider->initWithExistingContext(this,
239                                                 manager->m_providers[i]);
240         if (ret == false) {
241             releaseProvider(i);
242             break;
243         }
244     }
245
246     return ret;
247 }
248
249 /*
250  * Initialize a context from a GSS credential and context.
251  */
252 bool
253 gss_eap_attr_ctx::initWithGssContext(const gss_cred_id_t cred,
254                                      const gss_ctx_id_t ctx)
255 {
256     bool ret = true;
257
258     if (cred != GSS_C_NO_CREDENTIAL &&
259         (cred->flags & GSS_EAP_DISABLE_LOCAL_ATTRS_FLAG)) {
260         m_flags |= ATTR_FLAG_DISABLE_LOCAL;
261     }
262
263     for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
264         gss_eap_attr_provider *provider;
265
266         if (!providerEnabled(i)) {
267             releaseProvider(i);
268             continue;
269         }
270
271         provider = m_providers[i];
272
273         ret = provider->initWithGssContext(this, cred, ctx);
274         if (ret == false) {
275             releaseProvider(i);
276             break;
277         }
278     }
279
280     return ret;
281 }
282
283 bool
284 gss_eap_attr_ctx::initWithJsonObject(JSONObject &obj)
285 {
286     bool ret = false;
287     bool foundSource[ATTR_TYPE_MAX + 1];
288     unsigned int type;
289
290     for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++)
291         foundSource[type] = false;
292
293     if (obj["version"].integer() != 1)
294         return false;
295
296     m_flags = obj["flags"].integer();
297
298     JSONObject sources = obj["sources"];
299
300     /* Initialize providers from serialized state */
301     for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) {
302         gss_eap_attr_provider *provider;
303         const char *key;
304
305         if (!providerEnabled(type)) {
306             releaseProvider(type);
307             continue;
308         }
309
310         provider = m_providers[type];
311         key = provider->name();
312         if (key == NULL)
313             continue;
314
315         JSONObject source = sources.get(key);
316         if (!source.isNull() &&
317             !provider->initWithJsonObject(this, source)) {
318             releaseProvider(type);
319             return false;
320         }
321
322         foundSource[type] = true;
323     }
324
325     /* Initialize remaining providers from initialized providers */
326     for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) {
327         gss_eap_attr_provider *provider;
328
329         if (foundSource[type] || !providerEnabled(type))
330             continue;
331
332         provider = m_providers[type];
333
334         ret = provider->initWithGssContext(this,
335                                            GSS_C_NO_CREDENTIAL,
336                                            GSS_C_NO_CONTEXT);
337         if (ret == false) {
338             releaseProvider(type);
339             return false;
340         }
341     }
342
343     return true;
344 }
345
346 JSONObject
347 gss_eap_attr_ctx::jsonRepresentation(void) const
348 {
349     JSONObject obj, sources;
350     unsigned int i;
351
352     obj.set("version", 1);
353     obj.set("flags", m_flags);
354
355     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
356         gss_eap_attr_provider *provider;
357         const char *key;
358
359         provider = m_providers[i];
360         if (provider == NULL)
361             continue; /* provider not initialised */
362
363         key = provider->name();
364         if (key == NULL)
365             continue; /* provider does not have state */
366
367         JSONObject source = provider->jsonRepresentation();
368         sources.set(key, source);
369     }
370
371     obj.set("sources", sources);
372
373     return obj;
374 }
375
376 /*
377  * Initialize a context from an exported context or name token
378  */
379 bool
380 gss_eap_attr_ctx::initWithBuffer(const gss_buffer_t buffer)
381 {
382     OM_uint32 major, minor;
383     bool ret;
384     char *s;
385     json_error_t error;
386
387     major = bufferToString(&minor, buffer, &s);
388     if (GSS_ERROR(major))
389         return false;
390
391     JSONObject obj = JSONObject::load(s, 0, &error);
392     if (!obj.isNull()) {
393         ret = initWithJsonObject(obj);
394     } else
395         ret = false;
396
397     GSSEAP_FREE(s);
398
399     return ret;
400 }
401
402 gss_eap_attr_ctx::~gss_eap_attr_ctx(void)
403 {
404     for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++)
405         delete m_providers[i];
406 }
407
408 /*
409  * Locate provider for a given type
410  */
411 gss_eap_attr_provider *
412 gss_eap_attr_ctx::getProvider(unsigned int type) const
413 {
414     assert(type >= ATTR_TYPE_MIN && type <= ATTR_TYPE_MAX);
415     return m_providers[type];
416 }
417
418 /*
419  * Get primary provider. Only the primary provider is serialised when
420  * gss_export_sec_context() or gss_export_name_composite() is called.
421  */
422 gss_eap_attr_provider *
423 gss_eap_attr_ctx::getPrimaryProvider(void) const
424 {
425     return m_providers[ATTR_TYPE_MIN];
426 }
427
428 /*
429  * Set an attribute
430  */
431 bool
432 gss_eap_attr_ctx::setAttribute(int complete,
433                                const gss_buffer_t attr,
434                                const gss_buffer_t value)
435 {
436     gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
437     unsigned int type;
438     gss_eap_attr_provider *provider;
439     bool ret = false;
440
441     decomposeAttributeName(attr, &type, &suffix);
442
443     provider = m_providers[type];
444     if (provider != NULL) {
445         ret = provider->setAttribute(complete,
446                                      (type == ATTR_TYPE_LOCAL) ? attr : &suffix,
447                                      value);
448     }
449
450     return ret;
451 }
452
453 /*
454  * Delete an attrbiute
455  */
456 bool
457 gss_eap_attr_ctx::deleteAttribute(const gss_buffer_t attr)
458 {
459     gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
460     unsigned int type;
461     gss_eap_attr_provider *provider;
462     bool ret = false;
463
464     decomposeAttributeName(attr, &type, &suffix);
465
466     provider = m_providers[type];
467     if (provider != NULL) {
468         ret = provider->deleteAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix);
469     }
470
471     return ret;
472 }
473
474 /*
475  * Enumerate attribute types with callback
476  */
477 bool
478 gss_eap_attr_ctx::getAttributeTypes(gss_eap_attr_enumeration_cb cb, void *data) const
479 {
480     bool ret = false;
481     size_t i;
482
483     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
484         gss_eap_attr_provider *provider = m_providers[i];
485
486         if (provider == NULL)
487             continue;
488
489         ret = provider->getAttributeTypes(cb, data);
490         if (ret == false)
491             break;
492     }
493
494     return ret;
495 }
496
497 struct eap_gss_get_attr_types_args {
498     unsigned int type;
499     gss_buffer_set_t attrs;
500 };
501
502 static bool
503 addAttribute(const gss_eap_attr_ctx *manager,
504              const gss_eap_attr_provider *provider GSSEAP_UNUSED,
505              const gss_buffer_t attribute,
506              void *data)
507 {
508     eap_gss_get_attr_types_args *args = (eap_gss_get_attr_types_args *)data;
509     gss_buffer_desc qualified;
510     OM_uint32 major, minor;
511
512     if (args->type != ATTR_TYPE_LOCAL) {
513         manager->composeAttributeName(args->type, attribute, &qualified);
514         major = gss_add_buffer_set_member(&minor, &qualified, &args->attrs);
515         gss_release_buffer(&minor, &qualified);
516     } else {
517         major = gss_add_buffer_set_member(&minor, attribute, &args->attrs);
518     }
519
520     return GSS_ERROR(major) == false;
521 }
522
523 /*
524  * Enumerate attribute types, output is buffer set
525  */
526 bool
527 gss_eap_attr_ctx::getAttributeTypes(gss_buffer_set_t *attrs)
528 {
529     eap_gss_get_attr_types_args args;
530     OM_uint32 major, minor;
531     bool ret = false;
532     unsigned int i;
533
534     major = gss_create_empty_buffer_set(&minor, attrs);
535     if (GSS_ERROR(major))
536         throw std::bad_alloc();
537
538     args.attrs = *attrs;
539
540     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
541         gss_eap_attr_provider *provider = m_providers[i];
542
543         args.type = i;
544
545         if (provider == NULL)
546             continue;
547
548         ret = provider->getAttributeTypes(addAttribute, (void *)&args);
549         if (ret == false)
550             break;
551     }
552
553     if (ret == false)
554         gss_release_buffer_set(&minor, attrs);
555
556     return ret;
557 }
558
559 /*
560  * Get attribute with given name
561  */
562 bool
563 gss_eap_attr_ctx::getAttribute(const gss_buffer_t attr,
564                                int *authenticated,
565                                int *complete,
566                                gss_buffer_t value,
567                                gss_buffer_t display_value,
568                                int *more) const
569 {
570     gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
571     unsigned int type;
572     gss_eap_attr_provider *provider;
573     bool ret;
574
575     decomposeAttributeName(attr, &type, &suffix);
576
577     provider = m_providers[type];
578     if (provider == NULL)
579         return false;
580
581     ret = provider->getAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix,
582                                  authenticated, complete,
583                                  value, display_value, more);
584
585     return ret;
586 }
587
588 /*
589  * Map attribute context to C++ object
590  */
591 gss_any_t
592 gss_eap_attr_ctx::mapToAny(int authenticated,
593                            gss_buffer_t type_id) const
594 {
595     unsigned int type;
596     gss_eap_attr_provider *provider;
597     gss_buffer_desc suffix;
598
599     decomposeAttributeName(type_id, &type, &suffix);
600
601     provider = m_providers[type];
602     if (provider == NULL)
603         return (gss_any_t)NULL;
604
605     return provider->mapToAny(authenticated, &suffix);
606 }
607
608 /*
609  * Release mapped context
610  */
611 void
612 gss_eap_attr_ctx::releaseAnyNameMapping(gss_buffer_t type_id,
613                                         gss_any_t input) const
614 {
615     unsigned int type;
616     gss_eap_attr_provider *provider;
617     gss_buffer_desc suffix;
618
619     decomposeAttributeName(type_id, &type, &suffix);
620
621     provider = m_providers[type];
622     if (provider != NULL)
623         provider->releaseAnyNameMapping(&suffix, input);
624 }
625
626 /*
627  * Export attribute context to buffer
628  */
629 void
630 gss_eap_attr_ctx::exportToBuffer(gss_buffer_t buffer) const
631 {
632     OM_uint32 minor;
633     char *s;
634
635     JSONObject obj = jsonRepresentation();
636
637 #if 0
638     obj.dump(stdout);
639 #endif
640
641     s = obj.dump(JSON_COMPACT);
642
643     if (GSS_ERROR(makeStringBuffer(&minor, s, buffer)))
644         throw std::bad_alloc();
645 }
646
647 /*
648  * Return soonest expiry time of providers
649  */
650 time_t
651 gss_eap_attr_ctx::getExpiryTime(void) const
652 {
653     unsigned int i;
654     time_t expiryTime = 0;
655
656     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
657         gss_eap_attr_provider *provider = m_providers[i];
658         time_t providerExpiryTime;
659
660         if (provider == NULL)
661             continue;
662
663         providerExpiryTime = provider->getExpiryTime();
664         if (providerExpiryTime == 0)
665             continue;
666
667         if (expiryTime == 0 || providerExpiryTime < expiryTime)
668             expiryTime = providerExpiryTime;
669     }
670
671     return expiryTime;
672 }
673
674 OM_uint32
675 gss_eap_attr_ctx::mapException(OM_uint32 *minor, std::exception &e) const
676 {
677     unsigned int i;
678     OM_uint32 major;
679
680     /* Errors we handle ourselves */
681     if (typeid(e) == typeid(std::bad_alloc)) {
682         major = GSS_S_FAILURE;
683         *minor = ENOMEM;
684         goto cleanup;
685     } else if (typeid(e) == typeid(JSONException)) {
686         major = GSS_S_BAD_NAME;
687         *minor = GSSEAP_BAD_ATTR_TOKEN;
688         gssEapSaveStatusInfo(*minor, "%s", e.what());
689         goto cleanup;
690     }
691
692     /* Errors we delegate to providers */
693     major = GSS_S_CONTINUE_NEEDED;
694
695     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
696         gss_eap_attr_provider *provider = m_providers[i];
697
698         if (provider == NULL)
699             continue;
700
701         major = provider->mapException(minor, e);
702         if (major != GSS_S_CONTINUE_NEEDED)
703             break;
704     }
705
706     if (major == GSS_S_CONTINUE_NEEDED) {
707         *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
708         major = GSS_S_FAILURE;
709     }
710
711 cleanup:
712     assert(GSS_ERROR(major));
713
714     return major;
715 }
716
717 /*
718  * Decompose attribute name into prefix and suffix
719  */
720 void
721 gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
722                                          gss_buffer_t prefix,
723                                          gss_buffer_t suffix)
724 {
725     char *p = NULL;
726     size_t i;
727
728     for (i = 0; i < attribute->length; i++) {
729         if (((char *)attribute->value)[i] == ' ') {
730             p = (char *)attribute->value + i + 1;
731             break;
732         }
733     }
734
735     prefix->value = attribute->value;
736     prefix->length = i;
737
738     if (p != NULL && *p != '\0')  {
739         suffix->length = attribute->length - 1 - prefix->length;
740         suffix->value = p;
741     } else {
742         suffix->length = 0;
743         suffix->value = NULL;
744     }
745 }
746
747 /*
748  * Decompose attribute name into type and suffix
749  */
750 void
751 gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
752                                          unsigned int *type,
753                                          gss_buffer_t suffix) const
754 {
755     gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
756
757     decomposeAttributeName(attribute, &prefix, suffix);
758     *type = attributePrefixToType(&prefix);
759 }
760
761 /*
762  * Compose attribute name from prefix, suffix; returns C++ string
763  */
764 std::string
765 gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
766                                        const gss_buffer_t suffix)
767 {
768     std::string str;
769
770     if (prefix == GSS_C_NO_BUFFER || prefix->length == 0)
771         return str;
772
773     str.append((const char *)prefix->value, prefix->length);
774
775     if (suffix != GSS_C_NO_BUFFER) {
776         str.append(" ");
777         str.append((const char *)suffix->value, suffix->length);
778     }
779
780     return str;
781 }
782
783 /*
784  * Compose attribute name from type, suffix; returns C++ string
785  */
786 std::string
787 gss_eap_attr_ctx::composeAttributeName(unsigned int type,
788                                        const gss_buffer_t suffix)
789 {
790     gss_buffer_desc prefix = attributeTypeToPrefix(type);
791
792     return composeAttributeName(&prefix, suffix);
793 }
794
795 /*
796  * Compose attribute name from prefix, suffix; returns GSS buffer
797  */
798 void
799 gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
800                                        const gss_buffer_t suffix,
801                                        gss_buffer_t attribute)
802 {
803     std::string str = composeAttributeName(prefix, suffix);
804
805     if (str.length() != 0) {
806         return duplicateBuffer(str, attribute);
807     } else {
808         attribute->length = 0;
809         attribute->value = NULL;
810     }
811 }
812
813 /*
814  * Compose attribute name from type, suffix; returns GSS buffer
815  */
816 void
817 gss_eap_attr_ctx::composeAttributeName(unsigned int type,
818                                        const gss_buffer_t suffix,
819                                        gss_buffer_t attribute) const
820 {
821     gss_buffer_desc prefix = attributeTypeToPrefix(type);
822
823     return composeAttributeName(&prefix, suffix, attribute);
824 }
825
826 /*
827  * C wrappers
828  */
829 OM_uint32
830 gssEapInquireName(OM_uint32 *minor,
831                   gss_name_t name,
832                   int *name_is_MN,
833                   gss_OID *MN_mech,
834                   gss_buffer_set_t *attrs)
835 {
836     OM_uint32 major;
837
838     if (name_is_MN != NULL)
839         *name_is_MN = (name->mechanismUsed != GSS_C_NULL_OID);
840
841     if (MN_mech != NULL) {
842         major = gssEapCanonicalizeOid(minor, name->mechanismUsed,
843                                       OID_FLAG_NULL_VALID, MN_mech);
844         if (GSS_ERROR(major))
845             return major;
846     }
847
848     if (name->attrCtx == NULL) {
849         *minor = GSSEAP_NO_ATTR_CONTEXT;
850         return GSS_S_UNAVAILABLE;
851     }
852
853     if (GSS_ERROR(gssEapAttrProvidersInit(minor))) {
854         return GSS_S_UNAVAILABLE;
855     }
856
857     if (attrs != NULL) {
858         try {
859             if (!name->attrCtx->getAttributeTypes(attrs)) {
860                 *minor = GSSEAP_NO_ATTR_CONTEXT;
861                 return GSS_S_UNAVAILABLE;
862             }
863         } catch (std::exception &e) {
864             return name->attrCtx->mapException(minor, e);
865         }
866     }
867
868     return GSS_S_COMPLETE;
869 }
870
871 OM_uint32
872 gssEapGetNameAttribute(OM_uint32 *minor,
873                        gss_name_t name,
874                        gss_buffer_t attr,
875                        int *authenticated,
876                        int *complete,
877                        gss_buffer_t value,
878                        gss_buffer_t display_value,
879                        int *more)
880 {
881     if (authenticated != NULL)
882         *authenticated = 0;
883     if (complete != NULL)
884         *complete = 0;
885
886     if (value != NULL) {
887         value->length = 0;
888         value->value = NULL;
889     }
890
891     if (display_value != NULL) {
892         display_value->length = 0;
893         display_value->value = NULL;
894     }
895
896     if (name->attrCtx == NULL) {
897         *minor = GSSEAP_NO_ATTR_CONTEXT;
898         return GSS_S_UNAVAILABLE;
899     }
900
901     if (GSS_ERROR(gssEapAttrProvidersInit(minor))) {
902         return GSS_S_UNAVAILABLE;
903     }
904
905     try {
906         if (!name->attrCtx->getAttribute(attr, authenticated, complete,
907                                          value, display_value, more)) {
908             *minor = GSSEAP_NO_SUCH_ATTR;
909             gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
910                                  (int)attr->length, (char *)attr->value);
911             return GSS_S_UNAVAILABLE;
912         }
913     } catch (std::exception &e) {
914         return name->attrCtx->mapException(minor, e);
915     }
916
917     return GSS_S_COMPLETE;
918 }
919
920 OM_uint32
921 gssEapDeleteNameAttribute(OM_uint32 *minor,
922                           gss_name_t name,
923                           gss_buffer_t attr)
924 {
925     if (name->attrCtx == NULL) {
926         *minor = GSSEAP_NO_ATTR_CONTEXT;
927         return GSS_S_UNAVAILABLE;
928     }
929
930     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
931         return GSS_S_UNAVAILABLE;
932
933     try {
934         if (!name->attrCtx->deleteAttribute(attr)) {
935             *minor = GSSEAP_NO_SUCH_ATTR;
936             gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
937                                  (int)attr->length, (char *)attr->value);
938             return GSS_S_UNAVAILABLE;
939         }
940     } catch (std::exception &e) {
941         return name->attrCtx->mapException(minor, e);
942     }
943
944     return GSS_S_COMPLETE;
945 }
946
947 OM_uint32
948 gssEapSetNameAttribute(OM_uint32 *minor,
949                        gss_name_t name,
950                        int complete,
951                        gss_buffer_t attr,
952                        gss_buffer_t value)
953 {
954     if (name->attrCtx == NULL) {
955         *minor = GSSEAP_NO_ATTR_CONTEXT;
956         return GSS_S_UNAVAILABLE;
957     }
958
959     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
960         return GSS_S_UNAVAILABLE;
961
962     try {
963         if (!name->attrCtx->setAttribute(complete, attr, value)) {
964              *minor = GSSEAP_NO_SUCH_ATTR;
965             gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
966                                  (int)attr->length, (char *)attr->value);
967             return GSS_S_UNAVAILABLE;
968         }
969     } catch (std::exception &e) {
970         return name->attrCtx->mapException(minor, e);
971     }
972
973     return GSS_S_COMPLETE;
974 }
975
976 OM_uint32
977 gssEapExportAttrContext(OM_uint32 *minor,
978                         gss_name_t name,
979                         gss_buffer_t buffer)
980 {
981     if (name->attrCtx == NULL) {
982         buffer->length = 0;
983         buffer->value = NULL;
984
985         return GSS_S_COMPLETE;
986     }
987
988     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
989         return GSS_S_UNAVAILABLE;
990
991     try {
992         name->attrCtx->exportToBuffer(buffer);
993     } catch (std::exception &e) {
994         return name->attrCtx->mapException(minor, e);
995     }
996
997     return GSS_S_COMPLETE;
998 }
999
1000 OM_uint32
1001 gssEapImportAttrContext(OM_uint32 *minor,
1002                         gss_buffer_t buffer,
1003                         gss_name_t name)
1004 {
1005     gss_eap_attr_ctx *ctx = NULL;
1006     OM_uint32 major = GSS_S_FAILURE;
1007
1008     assert(name->attrCtx == NULL);
1009
1010     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
1011         return GSS_S_UNAVAILABLE;
1012
1013     if (buffer->length == 0)
1014         return GSS_S_COMPLETE;
1015
1016     try {
1017         ctx = new gss_eap_attr_ctx();
1018
1019         if (ctx->initWithBuffer(buffer)) {
1020             name->attrCtx = ctx;
1021             major = GSS_S_COMPLETE;
1022             *minor = 0;
1023         } else {
1024             major = GSS_S_BAD_NAME;
1025             *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
1026         }
1027     } catch (std::exception &e) {
1028         if (ctx != NULL)
1029             major = ctx->mapException(minor, e);
1030     }
1031
1032     assert(major == GSS_S_COMPLETE || name->attrCtx == NULL);
1033
1034     if (GSS_ERROR(major))
1035         delete ctx;
1036
1037     return major;
1038 }
1039
1040 OM_uint32
1041 gssEapDuplicateAttrContext(OM_uint32 *minor,
1042                            gss_name_t in,
1043                            gss_name_t out)
1044 {
1045     gss_eap_attr_ctx *ctx = NULL;
1046     OM_uint32 major = GSS_S_FAILURE;
1047
1048     assert(out->attrCtx == NULL);
1049
1050     if (in->attrCtx == NULL) {
1051         *minor = 0;
1052         return GSS_S_COMPLETE;
1053     }
1054
1055     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
1056         return GSS_S_UNAVAILABLE;
1057
1058     try {
1059         ctx = new gss_eap_attr_ctx();
1060
1061         if (ctx->initWithExistingContext(in->attrCtx)) {
1062             out->attrCtx = ctx;
1063             major = GSS_S_COMPLETE;
1064             *minor = 0;
1065         } else {
1066             major = GSS_S_FAILURE;
1067             *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
1068         }
1069     } catch (std::exception &e) {
1070         major = in->attrCtx->mapException(minor, e);
1071     }
1072
1073     assert(major == GSS_S_COMPLETE || out->attrCtx == NULL);
1074
1075     if (GSS_ERROR(major))
1076         delete ctx;
1077
1078     return GSS_S_COMPLETE;
1079 }
1080
1081 OM_uint32
1082 gssEapMapNameToAny(OM_uint32 *minor,
1083                    gss_name_t name,
1084                    int authenticated,
1085                    gss_buffer_t type_id,
1086                    gss_any_t *output)
1087 {
1088     if (name->attrCtx == NULL) {
1089         *minor = GSSEAP_NO_ATTR_CONTEXT;
1090         return GSS_S_UNAVAILABLE;
1091     }
1092
1093     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
1094         return GSS_S_UNAVAILABLE;
1095
1096     try {
1097         *output = name->attrCtx->mapToAny(authenticated, type_id);
1098     } catch (std::exception &e) {
1099         return name->attrCtx->mapException(minor, e);
1100     }
1101
1102     return GSS_S_COMPLETE;
1103 }
1104
1105 OM_uint32
1106 gssEapReleaseAnyNameMapping(OM_uint32 *minor,
1107                             gss_name_t name,
1108                             gss_buffer_t type_id,
1109                             gss_any_t *input)
1110 {
1111     if (name->attrCtx == NULL) {
1112         *minor = GSSEAP_NO_ATTR_CONTEXT;
1113         return GSS_S_UNAVAILABLE;
1114     }
1115
1116     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
1117         return GSS_S_UNAVAILABLE;
1118
1119     try {
1120         if (*input != NULL)
1121             name->attrCtx->releaseAnyNameMapping(type_id, *input);
1122         *input = NULL;
1123     } catch (std::exception &e) {
1124         return name->attrCtx->mapException(minor, e);
1125     }
1126
1127     return GSS_S_COMPLETE;
1128 }
1129
1130 OM_uint32
1131 gssEapReleaseAttrContext(OM_uint32 *minor,
1132                          gss_name_t name)
1133 {
1134     if (name->attrCtx != NULL)
1135         delete name->attrCtx;
1136
1137     *minor = 0;
1138     return GSS_S_COMPLETE;
1139 }
1140
1141 /*
1142  * Public accessor for initialisng a context from a GSS context. Also
1143  * sets expiry time on GSS context as a side-effect.
1144  */
1145 OM_uint32
1146 gssEapCreateAttrContext(OM_uint32 *minor,
1147                         gss_cred_id_t gssCred,
1148                         gss_ctx_id_t gssCtx,
1149                         struct gss_eap_attr_ctx **pAttrContext,
1150                         time_t *pExpiryTime)
1151 {
1152     gss_eap_attr_ctx *ctx = NULL;
1153     OM_uint32 major;
1154
1155     assert(gssCtx != GSS_C_NO_CONTEXT);
1156
1157     *pAttrContext = NULL;
1158
1159     major = gssEapAttrProvidersInit(minor);
1160     if (GSS_ERROR(major))
1161         return major;
1162
1163     try {
1164         /* Set *pAttrContext here to for reentrancy */
1165         *pAttrContext = ctx = new gss_eap_attr_ctx();
1166
1167         if (ctx->initWithGssContext(gssCred, gssCtx)) {
1168             *pExpiryTime = ctx->getExpiryTime();
1169             major = GSS_S_COMPLETE;
1170             *minor = 0;
1171         } else {
1172             major = GSS_S_FAILURE;
1173             *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
1174         }
1175     } catch (std::exception &e) {
1176         if (ctx != NULL)
1177             major = ctx->mapException(minor, e);
1178     }
1179
1180     if (GSS_ERROR(major)) {
1181         delete ctx;
1182         *pAttrContext = NULL;
1183     }
1184
1185     return major;
1186 }