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