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