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