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