Change krbCred member to reauthCred to better clarify purpose
[moonshot.git] / 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     try {
858         if (!name->attrCtx->getAttributeTypes(attrs)) {
859             *minor = GSSEAP_NO_ATTR_CONTEXT;
860             return GSS_S_UNAVAILABLE;
861         }
862     } catch (std::exception &e) {
863         return name->attrCtx->mapException(minor, e);
864     }
865
866     return GSS_S_COMPLETE;
867 }
868
869 OM_uint32
870 gssEapGetNameAttribute(OM_uint32 *minor,
871                        gss_name_t name,
872                        gss_buffer_t attr,
873                        int *authenticated,
874                        int *complete,
875                        gss_buffer_t value,
876                        gss_buffer_t display_value,
877                        int *more)
878 {
879     if (authenticated != NULL)
880         *authenticated = 0;
881     if (complete != NULL)
882         *complete = 0;
883
884     if (value != NULL) {
885         value->length = 0;
886         value->value = NULL;
887     }
888
889     if (display_value != NULL) {
890         display_value->length = 0;
891         display_value->value = NULL;
892     }
893
894     if (name->attrCtx == NULL) {
895         *minor = GSSEAP_NO_ATTR_CONTEXT;
896         return GSS_S_UNAVAILABLE;
897     }
898
899     if (GSS_ERROR(gssEapAttrProvidersInit(minor))) {
900         return GSS_S_UNAVAILABLE;
901     }
902
903     try {
904         if (!name->attrCtx->getAttribute(attr, authenticated, complete,
905                                          value, display_value, more)) {
906             *minor = GSSEAP_NO_SUCH_ATTR;
907             gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
908                                  (int)attr->length, (char *)attr->value);
909             return GSS_S_UNAVAILABLE;
910         }
911     } catch (std::exception &e) {
912         return name->attrCtx->mapException(minor, e);
913     }
914
915     return GSS_S_COMPLETE;
916 }
917
918 OM_uint32
919 gssEapDeleteNameAttribute(OM_uint32 *minor,
920                           gss_name_t name,
921                           gss_buffer_t attr)
922 {
923     if (name->attrCtx == NULL) {
924         *minor = GSSEAP_NO_ATTR_CONTEXT;
925         return GSS_S_UNAVAILABLE;
926     }
927
928     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
929         return GSS_S_UNAVAILABLE;
930
931     try {
932         if (!name->attrCtx->deleteAttribute(attr)) {
933             *minor = GSSEAP_NO_SUCH_ATTR;
934             gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
935                                  (int)attr->length, (char *)attr->value);
936             return GSS_S_UNAVAILABLE;
937         }
938     } catch (std::exception &e) {
939         return name->attrCtx->mapException(minor, e);
940     }
941
942     return GSS_S_COMPLETE;
943 }
944
945 OM_uint32
946 gssEapSetNameAttribute(OM_uint32 *minor,
947                        gss_name_t name,
948                        int complete,
949                        gss_buffer_t attr,
950                        gss_buffer_t value)
951 {
952     if (name->attrCtx == NULL) {
953         *minor = GSSEAP_NO_ATTR_CONTEXT;
954         return GSS_S_UNAVAILABLE;
955     }
956
957     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
958         return GSS_S_UNAVAILABLE;
959
960     try {
961         if (!name->attrCtx->setAttribute(complete, attr, value)) {
962              *minor = GSSEAP_NO_SUCH_ATTR;
963             gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
964                                  (int)attr->length, (char *)attr->value);
965             return GSS_S_UNAVAILABLE;
966         }
967     } catch (std::exception &e) {
968         return name->attrCtx->mapException(minor, e);
969     }
970
971     return GSS_S_COMPLETE;
972 }
973
974 OM_uint32
975 gssEapExportAttrContext(OM_uint32 *minor,
976                         gss_name_t name,
977                         gss_buffer_t buffer)
978 {
979     if (name->attrCtx == NULL) {
980         buffer->length = 0;
981         buffer->value = NULL;
982
983         return GSS_S_COMPLETE;
984     }
985
986     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
987         return GSS_S_UNAVAILABLE;
988
989     try {
990         name->attrCtx->exportToBuffer(buffer);
991     } catch (std::exception &e) {
992         return name->attrCtx->mapException(minor, e);
993     }
994
995     return GSS_S_COMPLETE;
996 }
997
998 OM_uint32
999 gssEapImportAttrContext(OM_uint32 *minor,
1000                         gss_buffer_t buffer,
1001                         gss_name_t name)
1002 {
1003     gss_eap_attr_ctx *ctx = NULL;
1004     OM_uint32 major = GSS_S_FAILURE;
1005
1006     assert(name->attrCtx == NULL);
1007
1008     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
1009         return GSS_S_UNAVAILABLE;
1010
1011     if (buffer->length == 0)
1012         return GSS_S_COMPLETE;
1013
1014     try {
1015         ctx = new gss_eap_attr_ctx();
1016
1017         if (ctx->initWithBuffer(buffer)) {
1018             name->attrCtx = ctx;
1019             major = GSS_S_COMPLETE;
1020             *minor = 0;
1021         } else {
1022             major = GSS_S_BAD_NAME;
1023             *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
1024         }
1025     } catch (std::exception &e) {
1026         if (ctx != NULL)
1027             major = ctx->mapException(minor, e);
1028     }
1029
1030     assert(major == GSS_S_COMPLETE || name->attrCtx == NULL);
1031
1032     if (GSS_ERROR(major))
1033         delete ctx;
1034
1035     return major;
1036 }
1037
1038 OM_uint32
1039 gssEapDuplicateAttrContext(OM_uint32 *minor,
1040                            gss_name_t in,
1041                            gss_name_t out)
1042 {
1043     gss_eap_attr_ctx *ctx = NULL;
1044     OM_uint32 major = GSS_S_FAILURE;
1045
1046     assert(out->attrCtx == NULL);
1047
1048     if (in->attrCtx == NULL) {
1049         *minor = 0;
1050         return GSS_S_COMPLETE;
1051     }
1052
1053     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
1054         return GSS_S_UNAVAILABLE;
1055
1056     try {
1057         ctx = new gss_eap_attr_ctx();
1058
1059         if (ctx->initWithExistingContext(in->attrCtx)) {
1060             out->attrCtx = ctx;
1061             major = GSS_S_COMPLETE;
1062             *minor = 0;
1063         } else {
1064             major = GSS_S_FAILURE;
1065             *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
1066         }
1067     } catch (std::exception &e) {
1068         major = in->attrCtx->mapException(minor, e);
1069     }
1070
1071     assert(major == GSS_S_COMPLETE || out->attrCtx == NULL);
1072
1073     if (GSS_ERROR(major))
1074         delete ctx;
1075
1076     return GSS_S_COMPLETE;
1077 }
1078
1079 OM_uint32
1080 gssEapMapNameToAny(OM_uint32 *minor,
1081                    gss_name_t name,
1082                    int authenticated,
1083                    gss_buffer_t type_id,
1084                    gss_any_t *output)
1085 {
1086     if (name->attrCtx == NULL) {
1087         *minor = GSSEAP_NO_ATTR_CONTEXT;
1088         return GSS_S_UNAVAILABLE;
1089     }
1090
1091     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
1092         return GSS_S_UNAVAILABLE;
1093
1094     try {
1095         *output = name->attrCtx->mapToAny(authenticated, type_id);
1096     } catch (std::exception &e) {
1097         return name->attrCtx->mapException(minor, e);
1098     }
1099
1100     return GSS_S_COMPLETE;
1101 }
1102
1103 OM_uint32
1104 gssEapReleaseAnyNameMapping(OM_uint32 *minor,
1105                             gss_name_t name,
1106                             gss_buffer_t type_id,
1107                             gss_any_t *input)
1108 {
1109     if (name->attrCtx == NULL) {
1110         *minor = GSSEAP_NO_ATTR_CONTEXT;
1111         return GSS_S_UNAVAILABLE;
1112     }
1113
1114     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
1115         return GSS_S_UNAVAILABLE;
1116
1117     try {
1118         if (*input != NULL)
1119             name->attrCtx->releaseAnyNameMapping(type_id, *input);
1120         *input = NULL;
1121     } catch (std::exception &e) {
1122         return name->attrCtx->mapException(minor, e);
1123     }
1124
1125     return GSS_S_COMPLETE;
1126 }
1127
1128 OM_uint32
1129 gssEapReleaseAttrContext(OM_uint32 *minor,
1130                          gss_name_t name)
1131 {
1132     if (name->attrCtx != NULL)
1133         delete name->attrCtx;
1134
1135     *minor = 0;
1136     return GSS_S_COMPLETE;
1137 }
1138
1139 /*
1140  * Public accessor for initialisng a context from a GSS context. Also
1141  * sets expiry time on GSS context as a side-effect.
1142  */
1143 OM_uint32
1144 gssEapCreateAttrContext(OM_uint32 *minor,
1145                         gss_cred_id_t gssCred,
1146                         gss_ctx_id_t gssCtx,
1147                         struct gss_eap_attr_ctx **pAttrContext,
1148                         time_t *pExpiryTime)
1149 {
1150     gss_eap_attr_ctx *ctx = NULL;
1151     OM_uint32 major;
1152
1153     assert(gssCtx != GSS_C_NO_CONTEXT);
1154
1155     *pAttrContext = NULL;
1156
1157     major = gssEapAttrProvidersInit(minor);
1158     if (GSS_ERROR(major))
1159         return major;
1160
1161     try {
1162         /* Set *pAttrContext here to for reentrancy */
1163         *pAttrContext = ctx = new gss_eap_attr_ctx();
1164
1165         if (ctx->initWithGssContext(gssCred, gssCtx)) {
1166             *pExpiryTime = ctx->getExpiryTime();
1167             major = GSS_S_COMPLETE;
1168             *minor = 0;
1169         } else {
1170             major = GSS_S_FAILURE;
1171             *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
1172         }
1173     } catch (std::exception &e) {
1174         if (ctx != NULL)
1175             major = ctx->mapException(minor, e);
1176     }
1177
1178     if (GSS_ERROR(major)) {
1179         delete ctx;
1180         *pAttrContext = NULL;
1181     }
1182
1183     return major;
1184 }