use GSSEAP_ASSERT macro instead of assert
[moonshot.git] / moonshot / 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 GSSEAP_ONCE_CALLBACK(gssEapAttrProvidersInitInternal)
50 {
51     OM_uint32 major, minor;
52
53     GSSEAP_ASSERT(gssEapAttrProvidersInitStatus == GSS_S_UNAVAILABLE);
54
55     major = gssEapRadiusAttrProviderInit(&minor);
56     if (GSS_ERROR(major))
57         goto cleanup;
58
59 #ifdef HAVE_OPENSAML
60     major = gssEapSamlAttrProvidersInit(&minor);
61     if (GSS_ERROR(major))
62         goto cleanup;
63 #endif
64
65 #ifdef HAVE_SHIBRESOLVER
66     /* Allow Shibboleth initialization failure to be non-fatal */
67     gssEapLocalAttrProviderInit(&minor);
68 #endif
69
70 cleanup:
71 #ifdef GSSEAP_DEBUG
72     GSSEAP_ASSERT(major == GSS_S_COMPLETE);
73 #endif
74
75     gssEapAttrProvidersInitStatus = major;
76
77     GSSEAP_ONCE_LEAVE;
78 }
79
80 static OM_uint32
81 gssEapAttrProvidersInit(OM_uint32 *minor)
82 {
83     GSSEAP_ONCE(&gssEapAttrProvidersInitOnce, gssEapAttrProvidersInitInternal);
84
85     if (GSS_ERROR(gssEapAttrProvidersInitStatus))
86         *minor = GSSEAP_NO_ATTR_PROVIDERS;
87
88     return gssEapAttrProvidersInitStatus;
89 }
90
91 OM_uint32
92 gssEapAttrProvidersFinalize(OM_uint32 *minor)
93 {
94     if (gssEapAttrProvidersInitStatus == GSS_S_COMPLETE) {
95 #ifdef HAVE_SHIBRESOLVER
96         gssEapLocalAttrProviderFinalize(minor);
97 #endif
98 #ifdef HAVE_OPENSAML
99         gssEapSamlAttrProvidersFinalize(minor);
100 #endif
101         gssEapRadiusAttrProviderFinalize(minor);
102
103         gssEapAttrProvidersInitStatus = GSS_S_UNAVAILABLE;
104     }
105
106     return GSS_S_COMPLETE;
107 }
108
109 static gss_eap_attr_create_provider gssEapAttrFactories[ATTR_TYPE_MAX + 1];
110
111 /*
112  * Register a provider for a particular type and prefix
113  */
114 void
115 gss_eap_attr_ctx::registerProvider(unsigned int type,
116                                    gss_eap_attr_create_provider factory)
117 {
118     GSSEAP_ASSERT(type <= ATTR_TYPE_MAX);
119
120     GSSEAP_ASSERT(gssEapAttrFactories[type] == NULL);
121
122     gssEapAttrFactories[type] = factory;
123 }
124
125 /*
126  * Unregister a provider
127  */
128 void
129 gss_eap_attr_ctx::unregisterProvider(unsigned int type)
130 {
131     GSSEAP_ASSERT(type <= ATTR_TYPE_MAX);
132
133     gssEapAttrFactories[type] = NULL;
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) const
161 {
162     unsigned int i;
163
164     for (i = ATTR_TYPE_MIN; i < ATTR_TYPE_MAX; i++) {
165         const char *pprefix;
166
167         if (!providerEnabled(i))
168             continue;
169
170         pprefix = m_providers[i]->prefix();
171         if (pprefix == NULL)
172             continue;
173
174         if (strlen(pprefix) == prefix->length &&
175             memcmp(pprefix, prefix->value, prefix->length) == 0)
176             return i;
177     }
178
179     return ATTR_TYPE_LOCAL;
180 }
181
182 /*
183  * Convert a type to an attribute prefix
184  */
185 gss_buffer_desc
186 gss_eap_attr_ctx::attributeTypeToPrefix(unsigned int type) const
187 {
188     gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
189
190     if (type < ATTR_TYPE_MIN || type >= ATTR_TYPE_MAX)
191         return prefix;
192
193     if (!providerEnabled(type))
194         return prefix;
195
196     prefix.value = (void *)m_providers[type]->prefix();
197     if (prefix.value != NULL)
198         prefix.length = strlen((char *)prefix.value);
199
200     return prefix;
201 }
202
203 bool
204 gss_eap_attr_ctx::providerEnabled(unsigned int type) const
205 {
206     if (type == ATTR_TYPE_LOCAL &&
207         (m_flags & ATTR_FLAG_DISABLE_LOCAL))
208         return false;
209
210     if (m_providers[type] == NULL)
211         return false;
212
213     return true;
214 }
215
216 void
217 gss_eap_attr_ctx::releaseProvider(unsigned int type)
218 {
219     delete m_providers[type];
220     m_providers[type] = NULL;
221 }
222
223 /*
224  * Initialize a context from an existing context.
225  */
226 bool
227 gss_eap_attr_ctx::initWithExistingContext(const gss_eap_attr_ctx *manager)
228 {
229     bool ret = true;
230
231     m_flags = manager->m_flags;
232
233     for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
234         gss_eap_attr_provider *provider;
235
236         if (!providerEnabled(i)) {
237             releaseProvider(i);
238             continue;
239         }
240
241         provider = m_providers[i];
242
243         ret = provider->initWithExistingContext(this,
244                                                 manager->m_providers[i]);
245         if (ret == false) {
246             releaseProvider(i);
247             break;
248         }
249     }
250
251     return ret;
252 }
253
254 /*
255  * Initialize a context from a GSS credential and context.
256  */
257 bool
258 gss_eap_attr_ctx::initWithGssContext(const gss_cred_id_t cred,
259                                      const gss_ctx_id_t ctx)
260 {
261     bool ret = true;
262
263     if (cred != GSS_C_NO_CREDENTIAL &&
264         (cred->flags & GSS_EAP_DISABLE_LOCAL_ATTRS_FLAG)) {
265         m_flags |= ATTR_FLAG_DISABLE_LOCAL;
266     }
267
268     for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
269         gss_eap_attr_provider *provider;
270
271         if (!providerEnabled(i)) {
272             releaseProvider(i);
273             continue;
274         }
275
276         provider = m_providers[i];
277
278         ret = provider->initWithGssContext(this, cred, ctx);
279         if (ret == false) {
280             releaseProvider(i);
281             break;
282         }
283     }
284
285     return ret;
286 }
287
288 bool
289 gss_eap_attr_ctx::initWithJsonObject(JSONObject &obj)
290 {
291     bool ret = false;
292     bool foundSource[ATTR_TYPE_MAX + 1];
293     unsigned int type;
294
295     for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++)
296         foundSource[type] = false;
297
298     if (obj["version"].integer() != 1)
299         return false;
300
301     m_flags = obj["flags"].integer();
302
303     JSONObject sources = obj["sources"];
304
305     /* Initialize providers from serialized state */
306     for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) {
307         gss_eap_attr_provider *provider;
308         const char *key;
309
310         if (!providerEnabled(type)) {
311             releaseProvider(type);
312             continue;
313         }
314
315         provider = m_providers[type];
316         key = provider->name();
317         if (key == NULL)
318             continue;
319
320         JSONObject source = sources.get(key);
321         if (!source.isNull() &&
322             !provider->initWithJsonObject(this, source)) {
323             releaseProvider(type);
324             return false;
325         }
326
327         foundSource[type] = true;
328     }
329
330     /* Initialize remaining providers from initialized providers */
331     for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) {
332         gss_eap_attr_provider *provider;
333
334         if (foundSource[type] || !providerEnabled(type))
335             continue;
336
337         provider = m_providers[type];
338
339         ret = provider->initWithGssContext(this,
340                                            GSS_C_NO_CREDENTIAL,
341                                            GSS_C_NO_CONTEXT);
342         if (ret == false) {
343             releaseProvider(type);
344             return false;
345         }
346     }
347
348     return true;
349 }
350
351 JSONObject
352 gss_eap_attr_ctx::jsonRepresentation(void) const
353 {
354     JSONObject obj, sources;
355     unsigned int i;
356
357     obj.set("version", 1);
358     obj.set("flags", m_flags);
359
360     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
361         gss_eap_attr_provider *provider;
362         const char *key;
363
364         provider = m_providers[i];
365         if (provider == NULL)
366             continue; /* provider not initialised */
367
368         key = provider->name();
369         if (key == NULL)
370             continue; /* provider does not have state */
371
372         JSONObject source = provider->jsonRepresentation();
373         sources.set(key, source);
374     }
375
376     obj.set("sources", sources);
377
378     return obj;
379 }
380
381 /*
382  * Initialize a context from an exported context or name token
383  */
384 bool
385 gss_eap_attr_ctx::initWithBuffer(const gss_buffer_t buffer)
386 {
387     OM_uint32 major, minor;
388     bool ret;
389     char *s;
390     json_error_t error;
391
392     major = bufferToString(&minor, buffer, &s);
393     if (GSS_ERROR(major))
394         return false;
395
396     JSONObject obj = JSONObject::load(s, 0, &error);
397     if (!obj.isNull()) {
398         ret = initWithJsonObject(obj);
399     } else
400         ret = false;
401
402     GSSEAP_FREE(s);
403
404     return ret;
405 }
406
407 gss_eap_attr_ctx::~gss_eap_attr_ctx(void)
408 {
409     for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++)
410         delete m_providers[i];
411 }
412
413 /*
414  * Locate provider for a given type
415  */
416 gss_eap_attr_provider *
417 gss_eap_attr_ctx::getProvider(unsigned int type) const
418 {
419     GSSEAP_ASSERT(type >= ATTR_TYPE_MIN && type <= ATTR_TYPE_MAX);
420     return m_providers[type];
421 }
422
423 /*
424  * Get primary provider. Only the primary provider is serialised when
425  * gss_export_sec_context() or gss_export_name_composite() is called.
426  */
427 gss_eap_attr_provider *
428 gss_eap_attr_ctx::getPrimaryProvider(void) const
429 {
430     return m_providers[ATTR_TYPE_MIN];
431 }
432
433 /*
434  * Set an attribute
435  */
436 bool
437 gss_eap_attr_ctx::setAttribute(int complete,
438                                const gss_buffer_t attr,
439                                const gss_buffer_t value)
440 {
441     gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
442     unsigned int type;
443     gss_eap_attr_provider *provider;
444     bool ret = false;
445
446     decomposeAttributeName(attr, &type, &suffix);
447
448     provider = m_providers[type];
449     if (provider != NULL) {
450         ret = provider->setAttribute(complete,
451                                      (type == ATTR_TYPE_LOCAL) ? attr : &suffix,
452                                      value);
453     }
454
455     return ret;
456 }
457
458 /*
459  * Delete an attrbiute
460  */
461 bool
462 gss_eap_attr_ctx::deleteAttribute(const gss_buffer_t attr)
463 {
464     gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
465     unsigned int type;
466     gss_eap_attr_provider *provider;
467     bool ret = false;
468
469     decomposeAttributeName(attr, &type, &suffix);
470
471     provider = m_providers[type];
472     if (provider != NULL) {
473         ret = provider->deleteAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix);
474     }
475
476     return ret;
477 }
478
479 /*
480  * Enumerate attribute types with callback
481  */
482 bool
483 gss_eap_attr_ctx::getAttributeTypes(gss_eap_attr_enumeration_cb cb, void *data) const
484 {
485     bool ret = false;
486     size_t i;
487
488     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
489         gss_eap_attr_provider *provider = m_providers[i];
490
491         if (provider == NULL)
492             continue;
493
494         ret = provider->getAttributeTypes(cb, data);
495         if (ret == false)
496             break;
497     }
498
499     return ret;
500 }
501
502 struct eap_gss_get_attr_types_args {
503     unsigned int type;
504     gss_buffer_set_t attrs;
505 };
506
507 static bool
508 addAttribute(const gss_eap_attr_ctx *manager,
509              const gss_eap_attr_provider *provider GSSEAP_UNUSED,
510              const gss_buffer_t attribute,
511              void *data)
512 {
513     eap_gss_get_attr_types_args *args = (eap_gss_get_attr_types_args *)data;
514     gss_buffer_desc qualified;
515     OM_uint32 major, minor;
516
517     if (args->type != ATTR_TYPE_LOCAL) {
518         manager->composeAttributeName(args->type, attribute, &qualified);
519         major = gss_add_buffer_set_member(&minor, &qualified, &args->attrs);
520         gss_release_buffer(&minor, &qualified);
521     } else {
522         major = gss_add_buffer_set_member(&minor, attribute, &args->attrs);
523     }
524
525     return GSS_ERROR(major) == false;
526 }
527
528 /*
529  * Enumerate attribute types, output is buffer set
530  */
531 bool
532 gss_eap_attr_ctx::getAttributeTypes(gss_buffer_set_t *attrs)
533 {
534     eap_gss_get_attr_types_args args;
535     OM_uint32 major, minor;
536     bool ret = false;
537     unsigned int i;
538
539     major = gss_create_empty_buffer_set(&minor, attrs);
540     if (GSS_ERROR(major))
541         throw std::bad_alloc();
542
543     args.attrs = *attrs;
544
545     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
546         gss_eap_attr_provider *provider = m_providers[i];
547
548         args.type = i;
549
550         if (provider == NULL)
551             continue;
552
553         ret = provider->getAttributeTypes(addAttribute, (void *)&args);
554         if (ret == false)
555             break;
556     }
557
558     if (ret == false)
559         gss_release_buffer_set(&minor, attrs);
560
561     return ret;
562 }
563
564 /*
565  * Get attribute with given name
566  */
567 bool
568 gss_eap_attr_ctx::getAttribute(const gss_buffer_t attr,
569                                int *authenticated,
570                                int *complete,
571                                gss_buffer_t value,
572                                gss_buffer_t display_value,
573                                int *more) const
574 {
575     gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
576     unsigned int type;
577     gss_eap_attr_provider *provider;
578     bool ret;
579
580     decomposeAttributeName(attr, &type, &suffix);
581
582     provider = m_providers[type];
583     if (provider == NULL)
584         return false;
585
586     ret = provider->getAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix,
587                                  authenticated, complete,
588                                  value, display_value, more);
589
590     return ret;
591 }
592
593 /*
594  * Map attribute context to C++ object
595  */
596 gss_any_t
597 gss_eap_attr_ctx::mapToAny(int authenticated,
598                            gss_buffer_t type_id) const
599 {
600     unsigned int type;
601     gss_eap_attr_provider *provider;
602     gss_buffer_desc suffix;
603
604     decomposeAttributeName(type_id, &type, &suffix);
605
606     provider = m_providers[type];
607     if (provider == NULL)
608         return (gss_any_t)NULL;
609
610     return provider->mapToAny(authenticated, &suffix);
611 }
612
613 /*
614  * Release mapped context
615  */
616 void
617 gss_eap_attr_ctx::releaseAnyNameMapping(gss_buffer_t type_id,
618                                         gss_any_t input) const
619 {
620     unsigned int type;
621     gss_eap_attr_provider *provider;
622     gss_buffer_desc suffix;
623
624     decomposeAttributeName(type_id, &type, &suffix);
625
626     provider = m_providers[type];
627     if (provider != NULL)
628         provider->releaseAnyNameMapping(&suffix, input);
629 }
630
631 /*
632  * Export attribute context to buffer
633  */
634 void
635 gss_eap_attr_ctx::exportToBuffer(gss_buffer_t buffer) const
636 {
637     OM_uint32 minor;
638     char *s;
639
640     JSONObject obj = jsonRepresentation();
641
642 #if 0
643     obj.dump(stdout);
644 #endif
645
646     s = obj.dump(JSON_COMPACT);
647
648     if (GSS_ERROR(makeStringBuffer(&minor, s, buffer)))
649         throw std::bad_alloc();
650 }
651
652 /*
653  * Return soonest expiry time of providers
654  */
655 time_t
656 gss_eap_attr_ctx::getExpiryTime(void) const
657 {
658     unsigned int i;
659     time_t expiryTime = 0;
660
661     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
662         gss_eap_attr_provider *provider = m_providers[i];
663         time_t providerExpiryTime;
664
665         if (provider == NULL)
666             continue;
667
668         providerExpiryTime = provider->getExpiryTime();
669         if (providerExpiryTime == 0)
670             continue;
671
672         if (expiryTime == 0 || providerExpiryTime < expiryTime)
673             expiryTime = providerExpiryTime;
674     }
675
676     return expiryTime;
677 }
678
679 OM_uint32
680 gss_eap_attr_ctx::mapException(OM_uint32 *minor, std::exception &e) const
681 {
682     unsigned int i;
683     OM_uint32 major;
684
685     /* Errors we handle ourselves */
686     if (typeid(e) == typeid(std::bad_alloc)) {
687         major = GSS_S_FAILURE;
688         *minor = ENOMEM;
689         goto cleanup;
690     } else if (typeid(e) == typeid(JSONException)) {
691         major = GSS_S_BAD_NAME;
692         *minor = GSSEAP_BAD_ATTR_TOKEN;
693         gssEapSaveStatusInfo(*minor, "%s", e.what());
694         goto cleanup;
695     }
696
697     /* Errors we delegate to providers */
698     major = GSS_S_CONTINUE_NEEDED;
699
700     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
701         gss_eap_attr_provider *provider = m_providers[i];
702
703         if (provider == NULL)
704             continue;
705
706         major = provider->mapException(minor, e);
707         if (major != GSS_S_CONTINUE_NEEDED)
708             break;
709     }
710
711     if (major == GSS_S_CONTINUE_NEEDED) {
712         *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
713         major = GSS_S_FAILURE;
714     }
715
716 cleanup:
717     GSSEAP_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     if (authenticated != NULL)
885         *authenticated = 0;
886     if (complete != NULL)
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     OM_uint32 major = GSS_S_FAILURE;
1010
1011     GSSEAP_ASSERT(name->attrCtx == NULL);
1012
1013     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
1014         return GSS_S_UNAVAILABLE;
1015
1016     if (buffer->length == 0)
1017         return GSS_S_COMPLETE;
1018
1019     try {
1020         ctx = new gss_eap_attr_ctx();
1021
1022         if (ctx->initWithBuffer(buffer)) {
1023             name->attrCtx = ctx;
1024             major = GSS_S_COMPLETE;
1025             *minor = 0;
1026         } else {
1027             major = GSS_S_BAD_NAME;
1028             *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
1029         }
1030     } catch (std::exception &e) {
1031         if (ctx != NULL)
1032             major = ctx->mapException(minor, e);
1033     }
1034
1035     GSSEAP_ASSERT(major == GSS_S_COMPLETE || name->attrCtx == NULL);
1036
1037     if (GSS_ERROR(major))
1038         delete ctx;
1039
1040     return major;
1041 }
1042
1043 OM_uint32
1044 gssEapDuplicateAttrContext(OM_uint32 *minor,
1045                            gss_name_t in,
1046                            gss_name_t out)
1047 {
1048     gss_eap_attr_ctx *ctx = NULL;
1049     OM_uint32 major = GSS_S_FAILURE;
1050
1051     GSSEAP_ASSERT(out->attrCtx == NULL);
1052
1053     if (in->attrCtx == NULL) {
1054         *minor = 0;
1055         return GSS_S_COMPLETE;
1056     }
1057
1058     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
1059         return GSS_S_UNAVAILABLE;
1060
1061     try {
1062         ctx = new gss_eap_attr_ctx();
1063
1064         if (ctx->initWithExistingContext(in->attrCtx)) {
1065             out->attrCtx = ctx;
1066             major = GSS_S_COMPLETE;
1067             *minor = 0;
1068         } else {
1069             major = GSS_S_FAILURE;
1070             *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
1071         }
1072     } catch (std::exception &e) {
1073         major = in->attrCtx->mapException(minor, e);
1074     }
1075
1076     GSSEAP_ASSERT(major == GSS_S_COMPLETE || out->attrCtx == NULL);
1077
1078     if (GSS_ERROR(major))
1079         delete ctx;
1080
1081     return GSS_S_COMPLETE;
1082 }
1083
1084 OM_uint32
1085 gssEapMapNameToAny(OM_uint32 *minor,
1086                    gss_name_t name,
1087                    int authenticated,
1088                    gss_buffer_t type_id,
1089                    gss_any_t *output)
1090 {
1091     if (name->attrCtx == NULL) {
1092         *minor = GSSEAP_NO_ATTR_CONTEXT;
1093         return GSS_S_UNAVAILABLE;
1094     }
1095
1096     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
1097         return GSS_S_UNAVAILABLE;
1098
1099     try {
1100         *output = name->attrCtx->mapToAny(authenticated, type_id);
1101     } catch (std::exception &e) {
1102         return name->attrCtx->mapException(minor, e);
1103     }
1104
1105     return GSS_S_COMPLETE;
1106 }
1107
1108 OM_uint32
1109 gssEapReleaseAnyNameMapping(OM_uint32 *minor,
1110                             gss_name_t name,
1111                             gss_buffer_t type_id,
1112                             gss_any_t *input)
1113 {
1114     if (name->attrCtx == NULL) {
1115         *minor = GSSEAP_NO_ATTR_CONTEXT;
1116         return GSS_S_UNAVAILABLE;
1117     }
1118
1119     if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
1120         return GSS_S_UNAVAILABLE;
1121
1122     try {
1123         if (*input != NULL)
1124             name->attrCtx->releaseAnyNameMapping(type_id, *input);
1125         *input = NULL;
1126     } catch (std::exception &e) {
1127         return name->attrCtx->mapException(minor, e);
1128     }
1129
1130     return GSS_S_COMPLETE;
1131 }
1132
1133 OM_uint32
1134 gssEapReleaseAttrContext(OM_uint32 *minor,
1135                          gss_name_t name)
1136 {
1137     if (name->attrCtx != NULL)
1138         delete name->attrCtx;
1139
1140     *minor = 0;
1141     return GSS_S_COMPLETE;
1142 }
1143
1144 /*
1145  * Public accessor for initialisng a context from a GSS context. Also
1146  * sets expiry time on GSS context as a side-effect.
1147  */
1148 OM_uint32
1149 gssEapCreateAttrContext(OM_uint32 *minor,
1150                         gss_cred_id_t gssCred,
1151                         gss_ctx_id_t gssCtx,
1152                         struct gss_eap_attr_ctx **pAttrContext,
1153                         time_t *pExpiryTime)
1154 {
1155     gss_eap_attr_ctx *ctx = NULL;
1156     OM_uint32 major;
1157
1158     GSSEAP_ASSERT(gssCtx != GSS_C_NO_CONTEXT);
1159
1160     *pAttrContext = NULL;
1161
1162     major = gssEapAttrProvidersInit(minor);
1163     if (GSS_ERROR(major))
1164         return major;
1165
1166     try {
1167         /* Set *pAttrContext here to for reentrancy */
1168         *pAttrContext = ctx = new gss_eap_attr_ctx();
1169
1170         if (ctx->initWithGssContext(gssCred, gssCtx)) {
1171             *pExpiryTime = ctx->getExpiryTime();
1172             major = GSS_S_COMPLETE;
1173             *minor = 0;
1174         } else {
1175             major = GSS_S_FAILURE;
1176             *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
1177         }
1178     } catch (std::exception &e) {
1179         if (ctx != NULL)
1180             major = ctx->mapException(minor, e);
1181     }
1182
1183     if (GSS_ERROR(major)) {
1184         delete ctx;
1185         *pAttrContext = NULL;
1186     }
1187
1188     return major;
1189 }