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