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