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