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