fix missing return statement in importing attributes
[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     if (ret == false)
337         return ret;
338
339     /*
340      * The call the initFromGssContext methods for attribute
341      * providers that can initialize themselves from other
342      * providers.
343      */
344     for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) {
345         gss_eap_attr_provider *provider;
346
347         if (didInit[type])
348             continue;
349
350         provider = m_providers[type];
351
352         ret = provider->initFromGssContext(this,
353                                            GSS_C_NO_CREDENTIAL,
354                                            GSS_C_NO_CONTEXT);
355         if (ret == false) {
356             releaseProvider(type);
357             break;
358         }
359     }
360
361     return ret;
362 }
363
364 gss_eap_attr_ctx::~gss_eap_attr_ctx(void)
365 {
366     for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++)
367         delete m_providers[i];
368 }
369
370 /*
371  * Locate provider for a given type
372  */
373 gss_eap_attr_provider *
374 gss_eap_attr_ctx::getProvider(unsigned int type) const
375 {
376     assert(type >= ATTR_TYPE_MIN && type <= ATTR_TYPE_MAX);
377     return m_providers[type];
378 }
379
380 /*
381  * Locate provider for a given prefix
382  */
383 gss_eap_attr_provider *
384 gss_eap_attr_ctx::getProvider(const gss_buffer_t prefix) const
385 {
386     unsigned int type;
387
388     type = attributePrefixToType(prefix);
389
390     return m_providers[type];
391 }
392
393 /*
394  * Get primary provider. Only the primary provider is serialised when
395  * gss_export_sec_context() or gss_export_name_composite() is called.
396  */
397 gss_eap_attr_provider *
398 gss_eap_attr_ctx::getPrimaryProvider(void) const
399 {
400     return m_providers[ATTR_TYPE_MIN];
401 }
402
403 /*
404  * Set an attribute
405  */
406 bool
407 gss_eap_attr_ctx::setAttribute(int complete,
408                                const gss_buffer_t attr,
409                                const gss_buffer_t value)
410 {
411     gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
412     unsigned int type;
413     gss_eap_attr_provider *provider;
414     bool ret = false;
415
416     decomposeAttributeName(attr, &type, &suffix);
417
418     provider = m_providers[type];
419     if (provider != NULL) {
420         ret = provider->setAttribute(complete,
421                                      (type == ATTR_TYPE_LOCAL) ? attr : &suffix,
422                                      value);
423     }
424
425     return ret;
426 }
427
428 /*
429  * Delete an attrbiute
430  */
431 bool
432 gss_eap_attr_ctx::deleteAttribute(const gss_buffer_t attr)
433 {
434     gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
435     unsigned int type;
436     gss_eap_attr_provider *provider;
437     bool ret = false;
438
439     decomposeAttributeName(attr, &type, &suffix);
440
441     provider = m_providers[type];
442     if (provider != NULL) {
443         ret = provider->deleteAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix);
444     }
445
446     return ret;
447 }
448
449 /*
450  * Enumerate attribute types with callback
451  */
452 bool
453 gss_eap_attr_ctx::getAttributeTypes(gss_eap_attr_enumeration_cb cb, void *data) const
454 {
455     bool ret = false;
456     size_t i;
457
458     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
459         gss_eap_attr_provider *provider = m_providers[i];
460
461         if (provider == NULL)
462             continue;
463
464         ret = provider->getAttributeTypes(cb, data);
465         if (ret == false)
466             break;
467     }
468
469     return ret;
470 }
471
472 struct eap_gss_get_attr_types_args {
473     unsigned int type;
474     gss_buffer_set_t attrs;
475 };
476
477 static bool
478 addAttribute(const gss_eap_attr_provider *provider GSSEAP_UNUSED,
479              const gss_buffer_t attribute,
480              void *data)
481 {
482     eap_gss_get_attr_types_args *args = (eap_gss_get_attr_types_args *)data;
483     gss_buffer_desc qualified;
484     OM_uint32 major, minor;
485
486     if (args->type != ATTR_TYPE_LOCAL) {
487         gss_eap_attr_ctx::composeAttributeName(args->type, attribute, &qualified);
488         major = gss_add_buffer_set_member(&minor, &qualified, &args->attrs);
489         gss_release_buffer(&minor, &qualified);
490     } else {
491         major = gss_add_buffer_set_member(&minor, attribute, &args->attrs);
492     }
493
494     return GSS_ERROR(major) == false;
495 }
496
497 /*
498  * Enumerate attribute types, output is buffer set
499  */
500 bool
501 gss_eap_attr_ctx::getAttributeTypes(gss_buffer_set_t *attrs)
502 {
503     eap_gss_get_attr_types_args args;
504     OM_uint32 major, minor;
505     bool ret = false;
506     unsigned int i;
507
508     major = gss_create_empty_buffer_set(&minor, attrs);
509     if (GSS_ERROR(major)) {
510         throw new std::bad_alloc;
511         return false;
512     }
513
514     args.attrs = *attrs;
515
516     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
517         gss_eap_attr_provider *provider = m_providers[i];
518
519         args.type = i;
520
521         if (provider == NULL)
522             continue;
523
524         ret = provider->getAttributeTypes(addAttribute, (void *)&args);
525         if (ret == false)
526             break;
527     }
528
529     if (ret == false)
530         gss_release_buffer_set(&minor, attrs);
531
532     return ret;
533 }
534
535 /*
536  * Get attribute with given name
537  */
538 bool
539 gss_eap_attr_ctx::getAttribute(const gss_buffer_t attr,
540                                int *authenticated,
541                                int *complete,
542                                gss_buffer_t value,
543                                gss_buffer_t display_value,
544                                int *more) const
545 {
546     gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
547     unsigned int type;
548     gss_eap_attr_provider *provider;
549     bool ret;
550
551     decomposeAttributeName(attr, &type, &suffix);
552
553     provider = m_providers[type];
554     if (provider == NULL)
555         return false;
556
557     ret = provider->getAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix,
558                                  authenticated, complete,
559                                  value, display_value, more);
560
561     return ret;
562 }
563
564 /*
565  * Map attribute context to C++ object
566  */
567 gss_any_t
568 gss_eap_attr_ctx::mapToAny(int authenticated,
569                            gss_buffer_t type_id) const
570 {
571     unsigned int type;
572     gss_eap_attr_provider *provider;
573     gss_buffer_desc suffix;
574
575     decomposeAttributeName(type_id, &type, &suffix);
576
577     provider = m_providers[type];
578     if (provider == NULL)
579         return (gss_any_t)NULL;
580
581     return provider->mapToAny(authenticated, &suffix);
582 }
583
584 /*
585  * Release mapped context
586  */
587 void
588 gss_eap_attr_ctx::releaseAnyNameMapping(gss_buffer_t type_id,
589                                         gss_any_t input) const
590 {
591     unsigned int type;
592     gss_eap_attr_provider *provider;
593     gss_buffer_desc suffix;
594
595     decomposeAttributeName(type_id, &type, &suffix);
596
597     provider = m_providers[type];
598     if (provider != NULL)
599         provider->releaseAnyNameMapping(&suffix, input);
600 }
601
602 /*
603  * Export attribute context to buffer
604  */
605 void
606 gss_eap_attr_ctx::exportToBuffer(gss_buffer_t buffer) const
607 {
608     OM_uint32 tmpMinor;
609     gss_buffer_desc providerTokens[ATTR_TYPE_MAX + 1];
610     size_t length = 4; /* m_flags */
611     unsigned char *p;
612     unsigned int i;
613
614     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
615         providerTokens[i].length = 0;
616         providerTokens[i].value = NULL;
617     }
618
619     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
620         gss_eap_attr_provider *provider = m_providers[i];
621
622         if (provider == NULL)
623             continue;
624
625         provider->exportToBuffer(&providerTokens[i]);
626
627         if (providerTokens[i].value != NULL)
628             length += 8 + providerTokens[i].length;
629     }
630
631     buffer->length = length;
632     buffer->value = GSSEAP_MALLOC(length);
633     if (buffer->value == NULL)
634         throw new std::bad_alloc;
635
636     p = (unsigned char *)buffer->value;
637     store_uint32_be(m_flags, p);
638     p += 4;
639
640     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
641         if (providerTokens[i].value == NULL)
642             continue;
643
644         store_uint32_be(i, p);
645         p += 4;
646         store_uint32_be(providerTokens[i].length, p);
647         p += 4;
648         memcpy(p, providerTokens[i].value, providerTokens[i].length);
649         p += providerTokens[i].length;
650
651         gss_release_buffer(&tmpMinor, &providerTokens[i]);
652     }
653 }
654
655 /*
656  * Return soonest expiry time of providers
657  */
658 time_t
659 gss_eap_attr_ctx::getExpiryTime(void) const
660 {
661     unsigned int i;
662     time_t expiryTime = 0;
663
664     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
665         gss_eap_attr_provider *provider = m_providers[i];
666         time_t providerExpiryTime;
667
668         if (provider == NULL)
669             continue;
670
671         providerExpiryTime = provider->getExpiryTime();
672         if (providerExpiryTime == 0)
673             continue;
674
675         if (expiryTime == 0 || providerExpiryTime < expiryTime)
676             expiryTime = providerExpiryTime;
677     }
678
679     return expiryTime;
680 }
681
682 OM_uint32
683 gss_eap_attr_ctx::mapException(OM_uint32 *minor, std::exception &e) const
684 {
685     unsigned int i;
686     OM_uint32 major;
687
688     /* Errors we handle ourselves */
689     major = GSS_S_FAILURE;
690
691     if (typeid(e) == typeid(std::bad_alloc)) {
692         *minor = ENOMEM;
693         goto cleanup;
694     }
695
696     /* Errors we delegate to providers */
697     major = GSS_S_CONTINUE_NEEDED;
698
699     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
700         gss_eap_attr_provider *provider = m_providers[i];
701
702         if (provider == NULL)
703             continue;
704
705         major = provider->mapException(minor, e);
706         if (major != GSS_S_CONTINUE_NEEDED)
707             break;
708     }
709
710     if (major == GSS_S_CONTINUE_NEEDED) {
711         *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
712         major = GSS_S_FAILURE;
713     }
714
715 cleanup:
716 #if 0
717     /* rethrow for now for debugging */
718     throw e;
719 #endif
720
721     assert(GSS_ERROR(major));
722
723     return major;
724 }
725
726 /*
727  * Decompose attribute name into prefix and suffix
728  */
729 void
730 gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
731                                          gss_buffer_t prefix,
732                                          gss_buffer_t suffix)
733 {
734     char *p = NULL;
735     size_t i;
736
737     for (i = 0; i < attribute->length; i++) {
738         if (((char *)attribute->value)[i] == ' ') {
739             p = (char *)attribute->value + i + 1;
740             break;
741         }
742     }
743
744     prefix->value = attribute->value;
745     prefix->length = i;
746
747     if (p != NULL && *p != '\0')  {
748         suffix->length = attribute->length - 1 - prefix->length;
749         suffix->value = p;
750     } else {
751         suffix->length = 0;
752         suffix->value = NULL;
753     }
754 }
755
756 /*
757  * Decompose attribute name into type and suffix
758  */
759 void
760 gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
761                                          unsigned int *type,
762                                          gss_buffer_t suffix)
763 {
764     gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
765
766     decomposeAttributeName(attribute, &prefix, suffix);
767     *type = attributePrefixToType(&prefix);
768 }
769
770 /*
771  * Compose attribute name from prefix, suffix; returns C++ string
772  */
773 std::string
774 gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
775                                        const gss_buffer_t suffix)
776 {
777     std::string str;
778
779     if (prefix == GSS_C_NO_BUFFER || prefix->length == 0)
780         return str;
781
782     str.append((const char *)prefix->value, prefix->length);
783
784     if (suffix != GSS_C_NO_BUFFER) {
785         str.append(" ");
786         str.append((const char *)suffix->value, suffix->length);
787     }
788
789     return str;
790 }
791
792 /*
793  * Compose attribute name from type, suffix; returns C++ string
794  */
795 std::string
796 gss_eap_attr_ctx::composeAttributeName(unsigned int type,
797                                        const gss_buffer_t suffix)
798 {
799     const gss_buffer_t prefix = attributeTypeToPrefix(type);
800
801     return composeAttributeName(prefix, suffix);
802 }
803
804 /*
805  * Compose attribute name from prefix, suffix; returns GSS buffer
806  */
807 void
808 gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
809                                        const gss_buffer_t suffix,
810                                        gss_buffer_t attribute)
811 {
812     std::string str = composeAttributeName(prefix, suffix);
813
814     if (str.length() != 0) {
815         return duplicateBuffer(str, attribute);
816     } else {
817         attribute->length = 0;
818         attribute->value = NULL;
819     }
820 }
821
822 /*
823  * Compose attribute name from type, suffix; returns GSS buffer
824  */
825 void
826 gss_eap_attr_ctx::composeAttributeName(unsigned int type,
827                                        const gss_buffer_t suffix,
828                                        gss_buffer_t attribute)
829 {
830     gss_buffer_t prefix = attributeTypeToPrefix(type);
831
832     return composeAttributeName(prefix, suffix, attribute);
833 }
834
835 /*
836  * C wrappers
837  */
838 OM_uint32
839 gssEapInquireName(OM_uint32 *minor,
840                   gss_name_t name,
841                   int *name_is_MN,
842                   gss_OID *MN_mech,
843                   gss_buffer_set_t *attrs)
844 {
845     OM_uint32 major;
846
847     if (name_is_MN != NULL)
848         *name_is_MN = (name->mechanismUsed != GSS_C_NULL_OID);
849
850     if (MN_mech != NULL) {
851         major = gssEapCanonicalizeOid(minor, name->mechanismUsed,
852                                       OID_FLAG_NULL_VALID, MN_mech);
853         if (GSS_ERROR(major))
854             return major;
855     }
856
857     if (name->attrCtx == NULL) {
858         *minor = GSSEAP_NO_ATTR_CONTEXT;
859         return GSS_S_UNAVAILABLE;
860     }
861
862     if (GSS_ERROR(gssEapAttrProvidersInit(minor))) {
863         return GSS_S_UNAVAILABLE;
864     }
865
866     try {
867         if (!name->attrCtx->getAttributeTypes(attrs)) {
868             *minor = GSSEAP_NO_ATTR_CONTEXT;
869             return GSS_S_UNAVAILABLE;
870         }
871     } catch (std::exception &e) {
872         return name->attrCtx->mapException(minor, e);
873     }
874
875     return GSS_S_COMPLETE;
876 }
877
878 OM_uint32
879 gssEapGetNameAttribute(OM_uint32 *minor,
880                        gss_name_t name,
881                        gss_buffer_t attr,
882                        int *authenticated,
883                        int *complete,
884                        gss_buffer_t value,
885                        gss_buffer_t display_value,
886                        int *more)
887 {
888     *authenticated = 0;
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_DEFECTIVE_TOKEN;
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         ctx = new gss_eap_attr_ctx();
1151         if (ctx->initFromGssContext(gssCred, gssCtx)) {
1152             *minor = 0;
1153             major = GSS_S_COMPLETE;
1154         } else {
1155             delete ctx;
1156         }
1157     } catch (std::exception &e) {
1158         if (ctx != NULL)
1159             major = ctx->mapException(minor, e);
1160     }
1161
1162     if (major == GSS_S_COMPLETE) {
1163         *pAttrContext = ctx;
1164         *pExpiryTime = ctx->getExpiryTime();
1165     }
1166
1167     return major;
1168 }