add JSON utility class
[mech_eap.git] / 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     obj.dump(stdout, JSON_INDENT(3));
633
634     s = obj.dump(JSON_COMPACT);
635
636     if (GSS_ERROR(makeStringBuffer(&minor, s, buffer)))
637         throw new std::bad_alloc;
638 }
639
640 /*
641  * Return soonest expiry time of providers
642  */
643 time_t
644 gss_eap_attr_ctx::getExpiryTime(void) const
645 {
646     unsigned int i;
647     time_t expiryTime = 0;
648
649     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
650         gss_eap_attr_provider *provider = m_providers[i];
651         time_t providerExpiryTime;
652
653         if (provider == NULL)
654             continue;
655
656         providerExpiryTime = provider->getExpiryTime();
657         if (providerExpiryTime == 0)
658             continue;
659
660         if (expiryTime == 0 || providerExpiryTime < expiryTime)
661             expiryTime = providerExpiryTime;
662     }
663
664     return expiryTime;
665 }
666
667 OM_uint32
668 gss_eap_attr_ctx::mapException(OM_uint32 *minor, std::exception &e) const
669 {
670     unsigned int i;
671     OM_uint32 major;
672
673     /* Errors we handle ourselves */
674     major = GSS_S_FAILURE;
675
676     if (typeid(e) == typeid(std::bad_alloc)) {
677         *minor = ENOMEM;
678         goto cleanup;
679     }
680
681     /* Errors we delegate to providers */
682     major = GSS_S_CONTINUE_NEEDED;
683
684     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
685         gss_eap_attr_provider *provider = m_providers[i];
686
687         if (provider == NULL)
688             continue;
689
690         major = provider->mapException(minor, e);
691         if (major != GSS_S_CONTINUE_NEEDED)
692             break;
693     }
694
695     if (major == GSS_S_CONTINUE_NEEDED) {
696         *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
697         major = GSS_S_FAILURE;
698     }
699
700 cleanup:
701 #if 0
702     /* rethrow for now for debugging */
703     throw e;
704 #endif
705
706     assert(GSS_ERROR(major));
707
708     return major;
709 }
710
711 /*
712  * Decompose attribute name into prefix and suffix
713  */
714 void
715 gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
716                                          gss_buffer_t prefix,
717                                          gss_buffer_t suffix)
718 {
719     char *p = NULL;
720     size_t i;
721
722     for (i = 0; i < attribute->length; i++) {
723         if (((char *)attribute->value)[i] == ' ') {
724             p = (char *)attribute->value + i + 1;
725             break;
726         }
727     }
728
729     prefix->value = attribute->value;
730     prefix->length = i;
731
732     if (p != NULL && *p != '\0')  {
733         suffix->length = attribute->length - 1 - prefix->length;
734         suffix->value = p;
735     } else {
736         suffix->length = 0;
737         suffix->value = NULL;
738     }
739 }
740
741 /*
742  * Decompose attribute name into type and suffix
743  */
744 void
745 gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
746                                          unsigned int *type,
747                                          gss_buffer_t suffix) const
748 {
749     gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
750
751     decomposeAttributeName(attribute, &prefix, suffix);
752     *type = attributePrefixToType(&prefix);
753 }
754
755 /*
756  * Compose attribute name from prefix, suffix; returns C++ string
757  */
758 std::string
759 gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
760                                        const gss_buffer_t suffix)
761 {
762     std::string str;
763
764     if (prefix == GSS_C_NO_BUFFER || prefix->length == 0)
765         return str;
766
767     str.append((const char *)prefix->value, prefix->length);
768
769     if (suffix != GSS_C_NO_BUFFER) {
770         str.append(" ");
771         str.append((const char *)suffix->value, suffix->length);
772     }
773
774     return str;
775 }
776
777 /*
778  * Compose attribute name from type, suffix; returns C++ string
779  */
780 std::string
781 gss_eap_attr_ctx::composeAttributeName(unsigned int type,
782                                        const gss_buffer_t suffix)
783 {
784     gss_buffer_desc prefix = attributeTypeToPrefix(type);
785
786     return composeAttributeName(&prefix, suffix);
787 }
788
789 /*
790  * Compose attribute name from prefix, suffix; returns GSS buffer
791  */
792 void
793 gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
794                                        const gss_buffer_t suffix,
795                                        gss_buffer_t attribute)
796 {
797     std::string str = composeAttributeName(prefix, suffix);
798
799     if (str.length() != 0) {
800         return duplicateBuffer(str, attribute);
801     } else {
802         attribute->length = 0;
803         attribute->value = NULL;
804     }
805 }
806
807 /*
808  * Compose attribute name from type, suffix; returns GSS buffer
809  */
810 void
811 gss_eap_attr_ctx::composeAttributeName(unsigned int type,
812                                        const gss_buffer_t suffix,
813                                        gss_buffer_t attribute) const
814 {
815     gss_buffer_desc prefix = attributeTypeToPrefix(type);
816
817     return composeAttributeName(&prefix, suffix, attribute);
818 }
819
820 /*
821  * C wrappers
822  */
823 OM_uint32
824 gssEapInquireName(OM_uint32 *minor,
825                   gss_name_t name,
826                   int *name_is_MN,
827                   gss_OID *MN_mech,
828                   gss_buffer_set_t *attrs)
829 {
830     OM_uint32 major;
831
832     if (name_is_MN != NULL)
833         *name_is_MN = (name->mechanismUsed != GSS_C_NULL_OID);
834
835     if (MN_mech != NULL) {
836         major = gssEapCanonicalizeOid(minor, name->mechanismUsed,
837                                       OID_FLAG_NULL_VALID, MN_mech);
838         if (GSS_ERROR(major))
839             return major;
840     }
841
842     if (name->attrCtx == NULL) {
843         *minor = GSSEAP_NO_ATTR_CONTEXT;
844         return GSS_S_UNAVAILABLE;
845     }
846
847     if (GSS_ERROR(gssEapAttrProvidersInit(minor))) {
848         return GSS_S_UNAVAILABLE;
849     }
850
851     try {
852         if (!name->attrCtx->getAttributeTypes(attrs)) {
853             *minor = GSSEAP_NO_ATTR_CONTEXT;
854             return GSS_S_UNAVAILABLE;
855         }
856     } catch (std::exception &e) {
857         return name->attrCtx->mapException(minor, e);
858     }
859
860     return GSS_S_COMPLETE;
861 }
862
863 OM_uint32
864 gssEapGetNameAttribute(OM_uint32 *minor,
865                        gss_name_t name,
866                        gss_buffer_t attr,
867                        int *authenticated,
868                        int *complete,
869                        gss_buffer_t value,
870                        gss_buffer_t display_value,
871                        int *more)
872 {
873     *authenticated = 0;
874     *complete = 0;
875
876     if (value != NULL) {
877         value->length = 0;
878         value->value = NULL;
879     }
880
881     if (display_value != NULL) {
882         display_value->length = 0;
883         display_value->value = NULL;
884     }
885
886     if (name->attrCtx == NULL) {
887         *minor = GSSEAP_NO_ATTR_CONTEXT;
888         return GSS_S_UNAVAILABLE;
889     }
890
891     if (GSS_ERROR(gssEapAttrProvidersInit(minor))) {
892         return GSS_S_UNAVAILABLE;
893     }
894
895     try {
896         if (!name->attrCtx->getAttribute(attr, authenticated, complete,
897                                          value, display_value, more)) {
898             *minor = GSSEAP_NO_SUCH_ATTR;
899             gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
900                                  (int)attr->length, (char *)attr->value);
901             return GSS_S_UNAVAILABLE;
902         }
903     } catch (std::exception &e) {
904         return name->attrCtx->mapException(minor, e);
905     }
906
907     return GSS_S_COMPLETE;
908 }
909
910 OM_uint32
911 gssEapDeleteNameAttribute(OM_uint32 *minor,
912                           gss_name_t name,
913                           gss_buffer_t attr)
914 {
915     if (name->attrCtx == NULL) {
916         *minor = GSSEAP_NO_ATTR_CONTEXT;
917         return GSS_S_UNAVAILABLE;
918     }
919
920     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
921         return GSS_S_UNAVAILABLE;
922
923     try {
924         if (!name->attrCtx->deleteAttribute(attr)) {
925             *minor = GSSEAP_NO_SUCH_ATTR;
926             gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
927                                  (int)attr->length, (char *)attr->value);
928             return GSS_S_UNAVAILABLE;
929         }
930     } catch (std::exception &e) {
931         return name->attrCtx->mapException(minor, e);
932     }
933
934     return GSS_S_COMPLETE;
935 }
936
937 OM_uint32
938 gssEapSetNameAttribute(OM_uint32 *minor,
939                        gss_name_t name,
940                        int complete,
941                        gss_buffer_t attr,
942                        gss_buffer_t value)
943 {
944     if (name->attrCtx == NULL) {
945         *minor = GSSEAP_NO_ATTR_CONTEXT;
946         return GSS_S_UNAVAILABLE;
947     }
948
949     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
950         return GSS_S_UNAVAILABLE;
951
952     try {
953         if (!name->attrCtx->setAttribute(complete, attr, value)) {
954              *minor = GSSEAP_NO_SUCH_ATTR;
955             gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
956                                  (int)attr->length, (char *)attr->value);
957             return GSS_S_UNAVAILABLE;
958         }
959     } catch (std::exception &e) {
960         return name->attrCtx->mapException(minor, e);
961     }
962
963     return GSS_S_COMPLETE;
964 }
965
966 OM_uint32
967 gssEapExportAttrContext(OM_uint32 *minor,
968                         gss_name_t name,
969                         gss_buffer_t buffer)
970 {
971     if (name->attrCtx == NULL) {
972         buffer->length = 0;
973         buffer->value = NULL;
974
975         return GSS_S_COMPLETE;
976     }
977
978     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
979         return GSS_S_UNAVAILABLE;
980
981     try {
982         name->attrCtx->exportToBuffer(buffer);
983     } catch (std::exception &e) {
984         return name->attrCtx->mapException(minor, e);
985     }
986
987     return GSS_S_COMPLETE;
988 }
989
990 OM_uint32
991 gssEapImportAttrContext(OM_uint32 *minor,
992                         gss_buffer_t buffer,
993                         gss_name_t name)
994 {
995     gss_eap_attr_ctx *ctx = NULL;
996
997     assert(name->attrCtx == NULL);
998
999     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
1000         return GSS_S_UNAVAILABLE;
1001
1002     if (buffer->length != 0) {
1003         try {
1004             ctx = new gss_eap_attr_ctx();
1005
1006             if (!ctx->initFromBuffer(buffer)) {
1007                 delete ctx;
1008                 *minor = GSSEAP_BAD_ATTR_TOKEN;
1009                 return GSS_S_DEFECTIVE_TOKEN;
1010             }
1011             name->attrCtx = ctx;
1012         } catch (std::exception &e) {
1013             delete ctx;
1014             return name->attrCtx->mapException(minor, e);
1015         }
1016     }
1017
1018     return GSS_S_COMPLETE;
1019 }
1020
1021 OM_uint32
1022 gssEapDuplicateAttrContext(OM_uint32 *minor,
1023                            gss_name_t in,
1024                            gss_name_t out)
1025 {
1026     gss_eap_attr_ctx *ctx = NULL;
1027
1028     assert(out->attrCtx == NULL);
1029
1030     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
1031         return GSS_S_UNAVAILABLE;
1032
1033     try {
1034         if (in->attrCtx != NULL) {
1035             ctx = new gss_eap_attr_ctx();
1036             if (!ctx->initFromExistingContext(in->attrCtx)) {
1037                 delete ctx;
1038                 *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
1039                 return GSS_S_FAILURE;
1040             }
1041             out->attrCtx = ctx;
1042         }
1043     } catch (std::exception &e) {
1044         delete ctx;
1045         return in->attrCtx->mapException(minor, e);
1046     }
1047
1048     return GSS_S_COMPLETE;
1049 }
1050
1051 OM_uint32
1052 gssEapMapNameToAny(OM_uint32 *minor,
1053                    gss_name_t name,
1054                    int authenticated,
1055                    gss_buffer_t type_id,
1056                    gss_any_t *output)
1057 {
1058     if (name->attrCtx == NULL) {
1059         *minor = GSSEAP_NO_ATTR_CONTEXT;
1060         return GSS_S_UNAVAILABLE;
1061     }
1062
1063     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
1064         return GSS_S_UNAVAILABLE;
1065
1066     try {
1067         *output = name->attrCtx->mapToAny(authenticated, type_id);
1068     } catch (std::exception &e) {
1069         return name->attrCtx->mapException(minor, e);
1070     }
1071
1072     return GSS_S_COMPLETE;
1073 }
1074
1075 OM_uint32
1076 gssEapReleaseAnyNameMapping(OM_uint32 *minor,
1077                             gss_name_t name,
1078                             gss_buffer_t type_id,
1079                             gss_any_t *input)
1080 {
1081     if (name->attrCtx == NULL) {
1082         *minor = GSSEAP_NO_ATTR_CONTEXT;
1083         return GSS_S_UNAVAILABLE;
1084     }
1085
1086     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
1087         return GSS_S_UNAVAILABLE;
1088
1089     try {
1090         if (*input != NULL)
1091             name->attrCtx->releaseAnyNameMapping(type_id, *input);
1092         *input = NULL;
1093     } catch (std::exception &e) {
1094         return name->attrCtx->mapException(minor, e);
1095     }
1096
1097     return GSS_S_COMPLETE;
1098 }
1099
1100 OM_uint32
1101 gssEapReleaseAttrContext(OM_uint32 *minor,
1102                          gss_name_t name)
1103 {
1104     if (name->attrCtx != NULL)
1105         delete name->attrCtx;
1106
1107     *minor = 0;
1108     return GSS_S_COMPLETE;
1109 }
1110
1111 /*
1112  * Public accessor for initialisng a context from a GSS context. Also
1113  * sets expiry time on GSS context as a side-effect.
1114  */
1115 OM_uint32
1116 gssEapCreateAttrContext(OM_uint32 *minor,
1117                         gss_cred_id_t gssCred,
1118                         gss_ctx_id_t gssCtx,
1119                         struct gss_eap_attr_ctx **pAttrContext,
1120                         time_t *pExpiryTime)
1121 {
1122     gss_eap_attr_ctx *ctx = NULL;
1123     OM_uint32 major;
1124
1125     assert(gssCtx != GSS_C_NO_CONTEXT);
1126
1127     major = gssEapAttrProvidersInit(minor);
1128     if (GSS_ERROR(major))
1129         return major;
1130
1131     *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
1132     major = GSS_S_FAILURE;
1133
1134     try {
1135         ctx = new gss_eap_attr_ctx();
1136         if (ctx->initFromGssContext(gssCred, gssCtx)) {
1137             *minor = 0;
1138             major = GSS_S_COMPLETE;
1139         } else {
1140             delete ctx;
1141         }
1142     } catch (std::exception &e) {
1143         if (ctx != NULL)
1144             major = ctx->mapException(minor, e);
1145     }
1146
1147     if (major == GSS_S_COMPLETE) {
1148         *pAttrContext = ctx;
1149         *pExpiryTime = ctx->getExpiryTime();
1150     }
1151
1152     return major;
1153 }