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