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