10f1ad4beb7a8be521c21f34f9a655d65d36d878
[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;
286     size_t remain = buffer->length;
287     unsigned char *p = (unsigned char *)buffer->value;
288     bool didInit[ATTR_TYPE_MAX + 1];
289
290     memset(didInit, 0, sizeof(didInit));
291
292     /* flags */
293     CHECK_REMAIN(4);
294     m_flags = load_uint32_be(p);
295     UPDATE_REMAIN(4);
296
297     while (remain) {
298         OM_uint32 type;
299         gss_buffer_desc providerToken;
300         gss_eap_attr_provider *provider;
301
302         /* TLV encoding of provider type, length, value */
303         CHECK_REMAIN(4);
304         type = load_uint32_be(p);
305         UPDATE_REMAIN(4);
306
307         CHECK_REMAIN(4);
308         providerToken.length = load_uint32_be(p);
309         UPDATE_REMAIN(4);
310
311         CHECK_REMAIN(providerToken.length);
312         providerToken.value = p;
313         UPDATE_REMAIN(providerToken.length);
314
315         if (type < ATTR_TYPE_MIN || type > ATTR_TYPE_MAX ||
316             didInit[type])
317             return false;
318
319         if (!providerEnabled(type)) {
320             releaseProvider(type);
321             continue;
322         }
323
324         provider = m_providers[type];
325
326         ret = provider->initFromBuffer(this, &providerToken);
327         if (ret == false) {
328             releaseProvider(type);
329             break;
330         }
331         didInit[type] = true;
332     }
333
334     for (size_t i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
335         gss_eap_attr_provider *provider;
336
337         if (didInit[i])
338             continue;
339
340         provider = m_providers[i];
341
342         ret = provider->initFromGssContext(this,
343                                            GSS_C_NO_CREDENTIAL,
344                                            GSS_C_NO_CONTEXT);
345         if (ret == false) {
346             releaseProvider(i);
347             break;
348         }
349     }
350
351     return ret;
352 }
353
354 gss_eap_attr_ctx::~gss_eap_attr_ctx(void)
355 {
356     for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++)
357         delete m_providers[i];
358 }
359
360 /*
361  * Locate provider for a given type
362  */
363 gss_eap_attr_provider *
364 gss_eap_attr_ctx::getProvider(unsigned int type) const
365 {
366     assert(type >= ATTR_TYPE_MIN && type <= ATTR_TYPE_MAX);
367     return m_providers[type];
368 }
369
370 /*
371  * Locate provider for a given prefix
372  */
373 gss_eap_attr_provider *
374 gss_eap_attr_ctx::getProvider(const gss_buffer_t prefix) const
375 {
376     unsigned int type;
377
378     type = attributePrefixToType(prefix);
379
380     return m_providers[type];
381 }
382
383 /*
384  * Get primary provider. Only the primary provider is serialised when
385  * gss_export_sec_context() or gss_export_name_composite() is called.
386  */
387 gss_eap_attr_provider *
388 gss_eap_attr_ctx::getPrimaryProvider(void) const
389 {
390     return m_providers[ATTR_TYPE_MIN];
391 }
392
393 /*
394  * Set an attribute
395  */
396 bool
397 gss_eap_attr_ctx::setAttribute(int complete,
398                                const gss_buffer_t attr,
399                                const gss_buffer_t value)
400 {
401     gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
402     unsigned int type;
403     gss_eap_attr_provider *provider;
404     bool ret = false;
405
406     decomposeAttributeName(attr, &type, &suffix);
407
408     provider = m_providers[type];
409     if (provider != NULL) {
410         ret = provider->setAttribute(complete,
411                                      (type == ATTR_TYPE_LOCAL) ? attr : &suffix,
412                                      value);
413     }
414
415     return ret;
416 }
417
418 /*
419  * Delete an attrbiute
420  */
421 bool
422 gss_eap_attr_ctx::deleteAttribute(const gss_buffer_t attr)
423 {
424     gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
425     unsigned int type;
426     gss_eap_attr_provider *provider;
427     bool ret = false;
428
429     decomposeAttributeName(attr, &type, &suffix);
430
431     provider = m_providers[type];
432     if (provider != NULL) {
433         ret = provider->deleteAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix);
434     }
435
436     return ret;
437 }
438
439 /*
440  * Enumerate attribute types with callback
441  */
442 bool
443 gss_eap_attr_ctx::getAttributeTypes(gss_eap_attr_enumeration_cb cb, void *data) const
444 {
445     bool ret = false;
446     size_t i;
447
448     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
449         gss_eap_attr_provider *provider = m_providers[i];
450
451         if (provider == NULL)
452             continue;
453
454         ret = provider->getAttributeTypes(cb, data);
455         if (ret == false)
456             break;
457     }
458
459     return ret;
460 }
461
462 struct eap_gss_get_attr_types_args {
463     unsigned int type;
464     gss_buffer_set_t attrs;
465 };
466
467 static bool
468 addAttribute(const gss_eap_attr_provider *provider GSSEAP_UNUSED,
469              const gss_buffer_t attribute,
470              void *data)
471 {
472     eap_gss_get_attr_types_args *args = (eap_gss_get_attr_types_args *)data;
473     gss_buffer_desc qualified;
474     OM_uint32 major, minor;
475
476     if (args->type != ATTR_TYPE_LOCAL) {
477         gss_eap_attr_ctx::composeAttributeName(args->type, attribute, &qualified);
478         major = gss_add_buffer_set_member(&minor, &qualified, &args->attrs);
479         gss_release_buffer(&minor, &qualified);
480     } else {
481         major = gss_add_buffer_set_member(&minor, attribute, &args->attrs);
482     }
483
484     return GSS_ERROR(major) == false;
485 }
486
487 /*
488  * Enumerate attribute types, output is buffer set
489  */
490 bool
491 gss_eap_attr_ctx::getAttributeTypes(gss_buffer_set_t *attrs)
492 {
493     eap_gss_get_attr_types_args args;
494     OM_uint32 major, minor;
495     bool ret = false;
496     unsigned int i;
497
498     major = gss_create_empty_buffer_set(&minor, attrs);
499     if (GSS_ERROR(major)) {
500         throw new std::bad_alloc;
501         return false;
502     }
503
504     args.attrs = *attrs;
505
506     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
507         gss_eap_attr_provider *provider = m_providers[i];
508
509         args.type = i;
510
511         if (provider == NULL)
512             continue;
513
514         ret = provider->getAttributeTypes(addAttribute, (void *)&args);
515         if (ret == false)
516             break;
517     }
518
519     if (ret == false)
520         gss_release_buffer_set(&minor, attrs);
521
522     return ret;
523 }
524
525 /*
526  * Get attribute with given name
527  */
528 bool
529 gss_eap_attr_ctx::getAttribute(const gss_buffer_t attr,
530                                int *authenticated,
531                                int *complete,
532                                gss_buffer_t value,
533                                gss_buffer_t display_value,
534                                int *more) const
535 {
536     gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
537     unsigned int type;
538     gss_eap_attr_provider *provider;
539     bool ret;
540
541     decomposeAttributeName(attr, &type, &suffix);
542
543     provider = m_providers[type];
544     if (provider == NULL)
545         return false;
546
547     ret = provider->getAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix,
548                                  authenticated, complete,
549                                  value, display_value, more);
550
551     return ret;
552 }
553
554 /*
555  * Map attribute context to C++ object
556  */
557 gss_any_t
558 gss_eap_attr_ctx::mapToAny(int authenticated,
559                            gss_buffer_t type_id) const
560 {
561     unsigned int type;
562     gss_eap_attr_provider *provider;
563     gss_buffer_desc suffix;
564
565     decomposeAttributeName(type_id, &type, &suffix);
566
567     provider = m_providers[type];
568     if (provider == NULL)
569         return (gss_any_t)NULL;
570
571     return provider->mapToAny(authenticated, &suffix);
572 }
573
574 /*
575  * Release mapped context
576  */
577 void
578 gss_eap_attr_ctx::releaseAnyNameMapping(gss_buffer_t type_id,
579                                         gss_any_t input) const
580 {
581     unsigned int type;
582     gss_eap_attr_provider *provider;
583     gss_buffer_desc suffix;
584
585     decomposeAttributeName(type_id, &type, &suffix);
586
587     provider = m_providers[type];
588     if (provider != NULL)
589         provider->releaseAnyNameMapping(&suffix, input);
590 }
591
592 /*
593  * Export attribute context to buffer
594  */
595 void
596 gss_eap_attr_ctx::exportToBuffer(gss_buffer_t buffer) const
597 {
598     OM_uint32 tmpMinor;
599     gss_buffer_desc providerTokens[ATTR_TYPE_MAX + 1];
600     size_t length = 4; /* m_flags */
601     unsigned char *p;
602
603     memset(providerTokens, 0, sizeof(providerTokens));
604
605     for (size_t i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
606         gss_eap_attr_provider *provider = m_providers[i];
607
608         if (provider == NULL)
609             continue;
610
611         provider->exportToBuffer(&providerTokens[i]);
612
613         if (providerTokens[i].value != NULL)
614             length += 8 + providerTokens[i].length;
615     }
616
617     buffer->length = length;
618     buffer->value = GSSEAP_MALLOC(length);
619     if (buffer->value == NULL)
620         throw new std::bad_alloc;
621
622     p = (unsigned char *)buffer->value;
623     store_uint32_be(m_flags, p);
624     p += 4;
625
626     for (size_t i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
627         if (providerTokens[i].value == NULL)
628             continue;
629
630         store_uint32_be(i, p);
631         p += 4;
632         store_uint32_be(providerTokens[i].length, p);
633         p += 4;
634         memcpy(p, providerTokens[i].value, providerTokens[i].length);
635         p += providerTokens[i].length;
636
637         gss_release_buffer(&tmpMinor, &providerTokens[i]);
638     }
639 }
640
641 /*
642  * Return soonest expiry time of providers
643  */
644 time_t
645 gss_eap_attr_ctx::getExpiryTime(void) const
646 {
647     unsigned int i;
648     time_t expiryTime = 0;
649
650     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
651         gss_eap_attr_provider *provider = m_providers[i];
652         time_t providerExpiryTime;
653
654         if (provider == NULL)
655             continue;
656
657         providerExpiryTime = provider->getExpiryTime();
658         if (providerExpiryTime == 0)
659             continue;
660
661         if (expiryTime == 0 || providerExpiryTime < expiryTime)
662             expiryTime = providerExpiryTime;
663     }
664
665     return expiryTime;
666 }
667
668 OM_uint32
669 gss_eap_attr_ctx::mapException(OM_uint32 *minor, std::exception &e) const
670 {
671     unsigned int i;
672     OM_uint32 major;
673
674     /* Errors we handle ourselves */
675     major = GSS_S_FAILURE;
676
677     if (typeid(e) == typeid(std::bad_alloc)) {
678         *minor = ENOMEM;
679         goto cleanup;
680     }
681
682     /* Errors we delegate to providers */
683     major = GSS_S_CONTINUE_NEEDED;
684
685     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
686         gss_eap_attr_provider *provider = m_providers[i];
687
688         if (provider == NULL)
689             continue;
690
691         major = provider->mapException(minor, e);
692         if (major != GSS_S_CONTINUE_NEEDED)
693             break;
694     }
695
696     if (major == GSS_S_CONTINUE_NEEDED) {
697         *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
698         major = GSS_S_FAILURE;
699     }
700
701 cleanup:
702 #if 0
703     /* rethrow for now for debugging */
704     throw e;
705 #endif
706
707     assert(GSS_ERROR(major));
708
709     return major;
710 }
711
712 /*
713  * Decompose attribute name into prefix and suffix
714  */
715 void
716 gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
717                                          gss_buffer_t prefix,
718                                          gss_buffer_t suffix)
719 {
720     char *p = NULL;
721     size_t i;
722
723     for (i = 0; i < attribute->length; i++) {
724         if (((char *)attribute->value)[i] == ' ') {
725             p = (char *)attribute->value + i + 1;
726             break;
727         }
728     }
729
730     prefix->value = attribute->value;
731     prefix->length = i;
732
733     if (p != NULL && *p != '\0')  {
734         suffix->length = attribute->length - 1 - prefix->length;
735         suffix->value = p;
736     } else {
737         suffix->length = 0;
738         suffix->value = NULL;
739     }
740 }
741
742 /*
743  * Decompose attribute name into type and suffix
744  */
745 void
746 gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
747                                          unsigned int *type,
748                                          gss_buffer_t suffix)
749 {
750     gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
751
752     decomposeAttributeName(attribute, &prefix, suffix);
753     *type = attributePrefixToType(&prefix);
754 }
755
756 /*
757  * Compose attribute name from prefix, suffix; returns C++ string
758  */
759 std::string
760 gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
761                                        const gss_buffer_t suffix)
762 {
763     std::string str;
764
765     if (prefix == GSS_C_NO_BUFFER || prefix->length == 0)
766         return str;
767
768     str.append((const char *)prefix->value, prefix->length);
769
770     if (suffix != GSS_C_NO_BUFFER) {
771         str.append(" ");
772         str.append((const char *)suffix->value, suffix->length);
773     }
774
775     return str;
776 }
777
778 /*
779  * Compose attribute name from type, suffix; returns C++ string
780  */
781 std::string
782 gss_eap_attr_ctx::composeAttributeName(unsigned int type,
783                                        const gss_buffer_t suffix)
784 {
785     const gss_buffer_t prefix = attributeTypeToPrefix(type);
786
787     return composeAttributeName(prefix, suffix);
788 }
789
790 /*
791  * Compose attribute name from prefix, suffix; returns GSS buffer
792  */
793 void
794 gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
795                                        const gss_buffer_t suffix,
796                                        gss_buffer_t attribute)
797 {
798     std::string str = composeAttributeName(prefix, suffix);
799
800     if (str.length() != 0) {
801         return duplicateBuffer(str, attribute);
802     } else {
803         attribute->length = 0;
804         attribute->value = NULL;
805     }
806 }
807
808 /*
809  * Compose attribute name from type, suffix; returns GSS buffer
810  */
811 void
812 gss_eap_attr_ctx::composeAttributeName(unsigned int type,
813                                        const gss_buffer_t suffix,
814                                        gss_buffer_t attribute)
815 {
816     gss_buffer_t prefix = attributeTypeToPrefix(type);
817
818     return composeAttributeName(prefix, suffix, attribute);
819 }
820
821 /*
822  * C wrappers
823  */
824 OM_uint32
825 gssEapInquireName(OM_uint32 *minor,
826                   gss_name_t name,
827                   int *name_is_MN,
828                   gss_OID *MN_mech,
829                   gss_buffer_set_t *attrs)
830 {
831     OM_uint32 major;
832
833     if (name_is_MN != NULL)
834         *name_is_MN = (name->mechanismUsed != GSS_C_NULL_OID);
835
836     if (MN_mech != NULL) {
837         major = gssEapCanonicalizeOid(minor, name->mechanismUsed,
838                                       OID_FLAG_NULL_VALID, MN_mech);
839         if (GSS_ERROR(major))
840             return major;
841     }
842
843     if (name->attrCtx == NULL) {
844         *minor = GSSEAP_NO_ATTR_CONTEXT;
845         return GSS_S_UNAVAILABLE;
846     }
847
848     if (GSS_ERROR(gssEapAttrProvidersInit(minor))) {
849         return GSS_S_UNAVAILABLE;
850     }
851
852     try {
853         if (!name->attrCtx->getAttributeTypes(attrs)) {
854             *minor = GSSEAP_NO_ATTR_CONTEXT;
855             return GSS_S_UNAVAILABLE;
856         }
857     } catch (std::exception &e) {
858         return name->attrCtx->mapException(minor, e);
859     }
860
861     return GSS_S_COMPLETE;
862 }
863
864 OM_uint32
865 gssEapGetNameAttribute(OM_uint32 *minor,
866                        gss_name_t name,
867                        gss_buffer_t attr,
868                        int *authenticated,
869                        int *complete,
870                        gss_buffer_t value,
871                        gss_buffer_t display_value,
872                        int *more)
873 {
874     *authenticated = 0;
875     *complete = 0;
876
877     if (value != NULL) {
878         value->length = 0;
879         value->value = NULL;
880     }
881
882     if (display_value != NULL) {
883         display_value->length = 0;
884         display_value->value = NULL;
885     }
886
887     if (name->attrCtx == NULL) {
888         *minor = GSSEAP_NO_ATTR_CONTEXT;
889         return GSS_S_UNAVAILABLE;
890     }
891
892     if (GSS_ERROR(gssEapAttrProvidersInit(minor))) {
893         return GSS_S_UNAVAILABLE;
894     }
895
896     try {
897         if (!name->attrCtx->getAttribute(attr, authenticated, complete,
898                                          value, display_value, more)) {
899             *minor = GSSEAP_NO_SUCH_ATTR;
900             gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
901                                  (int)attr->length, (char *)attr->value);
902             return GSS_S_UNAVAILABLE;
903         }
904     } catch (std::exception &e) {
905         return name->attrCtx->mapException(minor, e);
906     }
907
908     return GSS_S_COMPLETE;
909 }
910
911 OM_uint32
912 gssEapDeleteNameAttribute(OM_uint32 *minor,
913                           gss_name_t name,
914                           gss_buffer_t attr)
915 {
916     if (name->attrCtx == NULL) {
917         *minor = GSSEAP_NO_ATTR_CONTEXT;
918         return GSS_S_UNAVAILABLE;
919     }
920
921     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
922         return GSS_S_UNAVAILABLE;
923
924     try {
925         if (!name->attrCtx->deleteAttribute(attr)) {
926             *minor = GSSEAP_NO_SUCH_ATTR;
927             gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
928                                  (int)attr->length, (char *)attr->value);
929             return GSS_S_UNAVAILABLE;
930         }
931     } catch (std::exception &e) {
932         return name->attrCtx->mapException(minor, e);
933     }
934
935     return GSS_S_COMPLETE;
936 }
937
938 OM_uint32
939 gssEapSetNameAttribute(OM_uint32 *minor,
940                        gss_name_t name,
941                        int complete,
942                        gss_buffer_t attr,
943                        gss_buffer_t value)
944 {
945     if (name->attrCtx == NULL) {
946         *minor = GSSEAP_NO_ATTR_CONTEXT;
947         return GSS_S_UNAVAILABLE;
948     }
949
950     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
951         return GSS_S_UNAVAILABLE;
952
953     try {
954         if (!name->attrCtx->setAttribute(complete, attr, value)) {
955              *minor = GSSEAP_NO_SUCH_ATTR;
956             gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
957                                  (int)attr->length, (char *)attr->value);
958             return GSS_S_UNAVAILABLE;
959         }
960     } catch (std::exception &e) {
961         return name->attrCtx->mapException(minor, e);
962     }
963
964     return GSS_S_COMPLETE;
965 }
966
967 OM_uint32
968 gssEapExportAttrContext(OM_uint32 *minor,
969                         gss_name_t name,
970                         gss_buffer_t buffer)
971 {
972     if (name->attrCtx == NULL) {
973         buffer->length = 0;
974         buffer->value = NULL;
975
976         return GSS_S_COMPLETE;
977     }
978
979     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
980         return GSS_S_UNAVAILABLE;
981
982     try {
983         name->attrCtx->exportToBuffer(buffer);
984     } catch (std::exception &e) {
985         return name->attrCtx->mapException(minor, e);
986     }
987
988     return GSS_S_COMPLETE;
989 }
990
991 OM_uint32
992 gssEapImportAttrContext(OM_uint32 *minor,
993                         gss_buffer_t buffer,
994                         gss_name_t name)
995 {
996     gss_eap_attr_ctx *ctx = NULL;
997
998     assert(name->attrCtx == NULL);
999
1000     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
1001         return GSS_S_UNAVAILABLE;
1002
1003     if (buffer->length != 0) {
1004         try {
1005             ctx = new gss_eap_attr_ctx();
1006
1007             if (!ctx->initFromBuffer(buffer)) {
1008                 delete ctx;
1009                 *minor = GSSEAP_BAD_ATTR_TOKEN;
1010                 return GSS_S_DEFECTIVE_TOKEN;
1011             }
1012             name->attrCtx = ctx;
1013         } catch (std::exception &e) {
1014             delete ctx;
1015             return name->attrCtx->mapException(minor, e);
1016         }
1017     }
1018
1019     return GSS_S_COMPLETE;
1020 }
1021
1022 OM_uint32
1023 gssEapDuplicateAttrContext(OM_uint32 *minor,
1024                            gss_name_t in,
1025                            gss_name_t out)
1026 {
1027     gss_eap_attr_ctx *ctx = NULL;
1028
1029     assert(out->attrCtx == NULL);
1030
1031     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
1032         return GSS_S_UNAVAILABLE;
1033
1034     try {
1035         if (in->attrCtx != NULL) {
1036             ctx = new gss_eap_attr_ctx();
1037             if (!ctx->initFromExistingContext(in->attrCtx)) {
1038                 delete ctx;
1039                 *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
1040                 return GSS_S_FAILURE;
1041             }
1042             out->attrCtx = ctx;
1043         }
1044     } catch (std::exception &e) {
1045         delete ctx;
1046         return in->attrCtx->mapException(minor, e);
1047     }
1048
1049     return GSS_S_COMPLETE;
1050 }
1051
1052 OM_uint32
1053 gssEapMapNameToAny(OM_uint32 *minor,
1054                    gss_name_t name,
1055                    int authenticated,
1056                    gss_buffer_t type_id,
1057                    gss_any_t *output)
1058 {
1059     if (name->attrCtx == NULL) {
1060         *minor = GSSEAP_NO_ATTR_CONTEXT;
1061         return GSS_S_UNAVAILABLE;
1062     }
1063
1064     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
1065         return GSS_S_UNAVAILABLE;
1066
1067     try {
1068         *output = name->attrCtx->mapToAny(authenticated, type_id);
1069     } catch (std::exception &e) {
1070         return name->attrCtx->mapException(minor, e);
1071     }
1072
1073     return GSS_S_COMPLETE;
1074 }
1075
1076 OM_uint32
1077 gssEapReleaseAnyNameMapping(OM_uint32 *minor,
1078                             gss_name_t name,
1079                             gss_buffer_t type_id,
1080                             gss_any_t *input)
1081 {
1082     if (name->attrCtx == NULL) {
1083         *minor = GSSEAP_NO_ATTR_CONTEXT;
1084         return GSS_S_UNAVAILABLE;
1085     }
1086
1087     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
1088         return GSS_S_UNAVAILABLE;
1089
1090     try {
1091         if (*input != NULL)
1092             name->attrCtx->releaseAnyNameMapping(type_id, *input);
1093         *input = NULL;
1094     } catch (std::exception &e) {
1095         return name->attrCtx->mapException(minor, e);
1096     }
1097
1098     return GSS_S_COMPLETE;
1099 }
1100
1101 OM_uint32
1102 gssEapReleaseAttrContext(OM_uint32 *minor,
1103                          gss_name_t name)
1104 {
1105     if (name->attrCtx != NULL)
1106         delete name->attrCtx;
1107
1108     *minor = 0;
1109     return GSS_S_COMPLETE;
1110 }
1111
1112 /*
1113  * Public accessor for initialisng a context from a GSS context. Also
1114  * sets expiry time on GSS context as a side-effect.
1115  */
1116 OM_uint32
1117 gssEapCreateAttrContext(OM_uint32 *minor,
1118                         gss_cred_id_t gssCred,
1119                         gss_ctx_id_t gssCtx,
1120                         struct gss_eap_attr_ctx **pAttrContext,
1121                         time_t *pExpiryTime)
1122 {
1123     gss_eap_attr_ctx *ctx = NULL;
1124     OM_uint32 major;
1125
1126     assert(gssCtx != GSS_C_NO_CONTEXT);
1127
1128     major = gssEapAttrProvidersInit(minor);
1129     if (GSS_ERROR(major))
1130         return major;
1131
1132     *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
1133     major = GSS_S_FAILURE;
1134
1135     try {
1136         ctx = new gss_eap_attr_ctx();
1137         if (ctx->initFromGssContext(gssCred, gssCtx)) {
1138             *minor = 0;
1139             major = GSS_S_COMPLETE;
1140         } else {
1141             delete ctx;
1142         }
1143     } catch (std::exception &e) {
1144         if (ctx != NULL)
1145             major = ctx->mapException(minor, e);
1146     }
1147
1148     if (major == GSS_S_COMPLETE) {
1149         *pAttrContext = ctx;
1150         *pExpiryTime = ctx->getExpiryTime();
1151     }
1152
1153     return major;
1154 }