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