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