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