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