some cleanup work on marshalling
[cyrus-sasl.git] / mech_eap / util_attr.cpp
1 /*
2  * Copyright (c) 2010, 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 #include "gssapiP_eap.h"
34
35 #include <string>
36 #include <exception>
37 #include <new>
38
39 static gss_eap_attr_create_factory
40 gss_eap_attr_factories[ATTR_TYPE_MAX] = {
41     gss_eap_radius_attr_provider::createAttrContext,
42     gss_eap_saml_assertion_provider::createAttrContext,
43     gss_eap_saml_attr_provider::createAttrContext,
44     gss_eap_shib_attr_provider::createAttrContext
45 };
46
47 gss_eap_attr_ctx::gss_eap_attr_ctx(void)
48 {
49     for (unsigned int i = 0; i < ATTR_TYPE_MAX; i++) {
50         gss_eap_attr_provider *provider;
51
52         provider = (gss_eap_attr_factories[i])();
53         if (provider != NULL)
54             m_providers[i] = provider;
55     }
56 }
57
58 bool
59 gss_eap_attr_ctx::initFromExistingContext(const gss_eap_attr_ctx *source,
60                                           const gss_eap_attr_provider *ctx)
61 {
62     if (!gss_eap_attr_provider::initFromExistingContext(this, ctx))
63         return false;
64
65     for (unsigned int i = 0; i < ATTR_TYPE_MAX; i++) {
66         gss_eap_attr_provider *provider;
67
68         provider = m_providers[i];
69         if (provider != NULL) {
70             if (!provider->initFromExistingContext(this, provider))
71                 return false;
72         }
73     }
74
75     return true;
76 }
77
78 bool
79 gss_eap_attr_ctx::initFromGssContext(const gss_eap_attr_ctx *source,
80                                      const gss_cred_id_t cred,
81                                      const gss_ctx_id_t ctx)
82 {
83     if (!gss_eap_attr_provider::initFromGssContext(this, cred, ctx))
84         return false;
85
86     for (unsigned int i = 0; i < ATTR_TYPE_MAX; i++) {
87         gss_eap_attr_provider *provider;
88
89         provider = m_providers[i];
90         if (provider != NULL) {
91             if (!provider->initFromGssContext(this, cred, ctx))
92                 return false;
93         }
94     }
95
96     return true;
97 }
98
99 gss_eap_attr_ctx::~gss_eap_attr_ctx(void)
100 {
101     for (unsigned int i = 0; i < ATTR_TYPE_MAX; i++)
102         delete m_providers[i];
103 }
104
105 bool
106 gss_eap_attr_ctx::init(void)
107 {
108     return gss_eap_radius_attr_provider::init() &&
109            gss_eap_saml_assertion_provider::init() &&
110            gss_eap_saml_attr_provider::init() &&
111            gss_eap_shib_attr_provider::init();
112 }
113
114 void
115 gss_eap_attr_ctx::finalize(void)
116 {
117     gss_eap_shib_attr_provider::finalize();
118     gss_eap_saml_attr_provider::finalize();
119     gss_eap_saml_assertion_provider::finalize();
120     gss_eap_radius_attr_provider::finalize();
121 }
122
123 gss_eap_attr_provider *
124 gss_eap_attr_ctx::getProvider(unsigned int type) const
125 {
126     return m_providers[type];
127 }
128
129 gss_eap_attr_provider *
130 gss_eap_attr_ctx::getProvider(const gss_buffer_t prefix) const
131 {
132     unsigned int type;
133
134     type = attributePrefixToType(prefix);
135
136     return m_providers[type];
137 }
138
139 void
140 gss_eap_attr_ctx::setAttribute(int complete,
141                                const gss_buffer_t attr,
142                                const gss_buffer_t value)
143 {
144     gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
145     unsigned int type;
146     gss_eap_attr_provider *provider;
147
148     decomposeAttributeName(attr, &type, &suffix);
149
150     provider = m_providers[type];
151     if (provider != NULL) {
152         provider->setAttribute(complete,
153                                (type == ATTR_TYPE_LOCAL) ? attr : &suffix,
154                                value);
155                                
156     }
157 }
158
159 void
160 gss_eap_attr_ctx::deleteAttribute(const gss_buffer_t attr)
161 {
162     gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
163     unsigned int type;
164     gss_eap_attr_provider *provider;
165
166     decomposeAttributeName(attr, &type, &suffix);
167
168     provider = m_providers[type];
169     if (provider != NULL) {
170         provider->deleteAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix);
171     }
172 }
173
174 bool
175 gss_eap_attr_ctx::getAttributeTypes(gss_eap_attr_enumeration_cb cb, void *data) const
176 {
177     bool ret = false;
178     size_t i;
179
180     for (i = 0; i < ATTR_TYPE_MAX; i++) {
181         gss_eap_attr_provider *provider;
182
183         provider = m_providers[i];
184         if (provider == NULL)
185             continue;
186
187         ret = provider->getAttributeTypes(cb, data);
188         if (ret == false)
189             break;
190     }
191
192     return ret;
193 }
194
195 struct eap_gss_get_attr_types_args {
196     unsigned int type;
197     gss_buffer_set_t attrs;
198 };
199
200 static bool
201 addAttribute(const gss_eap_attr_provider *provider,
202              const gss_buffer_t attribute,
203              void *data)
204 {
205     eap_gss_get_attr_types_args *args = (eap_gss_get_attr_types_args *)data;
206     gss_buffer_t prefix = GSS_C_NO_BUFFER;
207     gss_buffer_desc qualified;
208     OM_uint32 major, minor;
209
210     if (args->type != ATTR_TYPE_LOCAL) {
211         gss_eap_attr_ctx::composeAttributeName(args->type, attribute, &qualified);
212         major = gss_add_buffer_set_member(&minor, &qualified, &args->attrs);
213         gss_release_buffer(&minor, &qualified);
214     } else {
215         major = gss_add_buffer_set_member(&minor, prefix, &args->attrs);
216     }
217
218     return GSS_ERROR(major) ? false : true;
219 }
220
221 bool
222 gss_eap_attr_ctx::getAttributeTypes(gss_buffer_set_t *attrs)
223 {
224     eap_gss_get_attr_types_args args;
225     OM_uint32 major, minor;
226     bool ret = false;
227     unsigned int i;
228
229     major = gss_create_empty_buffer_set(&minor, attrs);
230     if (GSS_ERROR(major)) {
231         throw new std::bad_alloc;
232         return false;
233     }
234
235     args.attrs = *attrs;
236
237     for (i = 0; i < ATTR_TYPE_MAX; i++) {
238         gss_eap_attr_provider *provider;
239
240         args.type = i;
241
242         provider = m_providers[i];
243         if (provider == NULL)
244             continue;
245
246         ret = provider->getAttributeTypes(addAttribute, (void *)&args);
247         if (ret == false)
248             break;
249     }
250
251     if (ret == false) {
252         gss_release_buffer_set(&minor, attrs);
253     }
254
255     return ret;
256 }
257
258 bool
259 gss_eap_attr_ctx::getAttribute(const gss_buffer_t attr,
260                                int *authenticated,
261                                int *complete,
262                                gss_buffer_t value,
263                                gss_buffer_t display_value,
264                                int *more) const
265 {
266     gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
267     unsigned int type;
268     gss_eap_attr_provider *provider;
269     bool ret;
270
271     decomposeAttributeName(attr, &type, &suffix);
272
273     provider = m_providers[type];
274     if (provider == NULL) {
275         *more = 0;
276         return false;
277     }
278
279     ret = provider->getAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix,
280                                  authenticated, complete,
281                                  value, display_value, more);
282
283     return ret;
284 }
285
286 gss_any_t
287 gss_eap_attr_ctx::mapToAny(int authenticated,
288                            gss_buffer_t type_id) const
289 {
290     return NULL;
291 }
292
293 void
294 gss_eap_attr_ctx::releaseAnyNameMapping(gss_buffer_t type_id,
295                                         gss_any_t input) const
296 {
297 }
298
299 void
300 gss_eap_attr_ctx::exportToBuffer(gss_buffer_t buffer) const
301 {
302     m_providers[ATTR_TYPE_RADIUS]->exportToBuffer(buffer);
303 }
304
305 bool
306 gss_eap_attr_ctx::initFromBuffer(const gss_eap_attr_ctx *ctx,
307                                  const gss_buffer_t buffer)
308 {
309     unsigned int i;
310     bool ret;
311
312     ret = m_providers[ATTR_TYPE_RADIUS]->initFromBuffer(this, buffer);
313     if (!ret)
314         return false;
315
316     for (i = ATTR_TYPE_RADIUS + 1; i < ATTR_TYPE_MAX; i++) {
317         gss_eap_attr_provider *provider = m_providers[i];
318
319         ret = provider->initFromGssContext(
320             this, GSS_C_NO_CREDENTIAL, GSS_C_NO_CONTEXT);
321         if (!ret)
322             break;
323     }
324
325     return ret;
326 }
327
328
329 /*
330  * C wrappers
331  */
332
333 static OM_uint32
334 mapException(OM_uint32 *minor, std::exception &e)
335 {
336     *minor = 0;
337     return GSS_S_FAILURE;
338 }
339
340 static gss_buffer_desc attributePrefixes[] = {
341     {
342         /* ATTR_TYPE_RADIUS_AVP */
343         sizeof("urn:ietf:params:gss-eap:radius-avp"),
344         (void *)"urn:ietf:params:gss-eap:radius-avp",
345     },
346     {
347         /* ATTR_TYPE_SAML_AAA_ASSERTION */
348         sizeof("urn:ietf:params:gss-eap:saml-aaa-assertion"),
349         (void *)"urn:ietf:params:gss-eap:saml-aaa-assertion"
350     },
351     {
352         /* ATTR_TYPE_SAML_ATTR */
353         sizeof("urn:ietf:params:gss-eap:saml-attr"),
354         (void *)"urn:ietf:params:gss-eap:saml-attr"
355     },
356 };
357
358 unsigned int
359 gss_eap_attr_ctx::attributePrefixToType(const gss_buffer_t prefix)
360 {
361     unsigned int i;
362
363     for (i = ATTR_TYPE_MIN;
364          i < sizeof(attributePrefixes) / sizeof(attributePrefixes[0]);
365          i++)
366     {
367         if (bufferEqual(&attributePrefixes[i], prefix))
368             return i;
369     }
370
371     return ATTR_TYPE_LOCAL;
372 }
373
374 const gss_buffer_t
375 gss_eap_attr_ctx::attributeTypeToPrefix(unsigned int type)
376 {
377     if (type < ATTR_TYPE_MIN || type >= ATTR_TYPE_LOCAL)
378         return GSS_C_NO_BUFFER;
379
380     return &attributePrefixes[type];
381 }
382
383 void
384 gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
385                                          gss_buffer_t prefix,
386                                          gss_buffer_t suffix)
387 {
388     char *p = NULL;
389     size_t i;
390
391     for (i = 0; i < attribute->length; i++) {
392         if (((char *)attribute->value)[i] == ' ') {
393             p = (char *)attribute->value + i + 1;
394             break;
395         }
396     }
397
398     prefix->value = attribute->value;
399     prefix->length = i;
400
401     if (p != NULL && *p != '\0')  {
402         suffix->length = attribute->length - 1 - prefix->length;
403         suffix->value = p;
404     } else {
405         suffix->length = 0;
406         suffix->value = NULL;
407     }
408 }
409
410 std::string
411 gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
412                                        const gss_buffer_t suffix)
413 {
414     std::string str;
415
416     if (prefix == GSS_C_NO_BUFFER || prefix->length == 0)
417         return str;
418
419     str.append((const char *)prefix->value, prefix->length);
420
421     if (suffix != GSS_C_NO_BUFFER) {
422         str.append(" ");
423         str.append((const char *)suffix->value, suffix->length);
424     }
425
426     return str;
427 }
428
429 std::string
430 gss_eap_attr_ctx::composeAttributeName(unsigned int type,
431                                        const gss_buffer_t suffix)
432 {
433     const gss_buffer_t prefix = attributeTypeToPrefix(type);
434
435     return composeAttributeName(prefix, suffix);
436 }
437
438 void
439 gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
440                                        const gss_buffer_t suffix,
441                                        gss_buffer_t attribute)
442 {
443     std::string str = composeAttributeName(prefix, suffix);
444
445     if (str.length() != 0) {
446         return duplicateBuffer(str, attribute);
447     } else {
448         attribute->length = 0;
449         attribute->value = NULL;
450     }
451 }
452
453 void
454 gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
455                                          unsigned int *type,
456                                          gss_buffer_t suffix)
457 {
458     gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
459
460     decomposeAttributeName(attribute, &prefix, suffix);
461     *type = attributePrefixToType(&prefix);
462 }
463
464 void
465 gss_eap_attr_ctx::composeAttributeName(unsigned int type,
466                                        const gss_buffer_t suffix,
467                                        gss_buffer_t attribute)
468 {
469     gss_buffer_t prefix = attributeTypeToPrefix(type);
470
471     return composeAttributeName(prefix, suffix, attribute);
472 }
473
474 OM_uint32
475 gssEapInquireName(OM_uint32 *minor,
476                   gss_name_t name,
477                   int *name_is_MN,
478                   gss_OID *MN_mech,
479                   gss_buffer_set_t *attrs)
480 {
481     if (name->attrCtx == NULL)
482         return GSS_S_UNAVAILABLE;
483
484     try {
485         if (!name->attrCtx->getAttributeTypes(attrs))
486             return GSS_S_UNAVAILABLE;
487     } catch (std::exception &e) {
488         return mapException(minor, e);
489     }
490
491     return GSS_S_COMPLETE;
492 }
493
494 OM_uint32
495 gssEapGetNameAttribute(OM_uint32 *minor,
496                        gss_name_t name,
497                        gss_buffer_t attr,
498                        int *authenticated,
499                        int *complete,
500                        gss_buffer_t value,
501                        gss_buffer_t display_value,
502                        int *more)
503 {
504     *authenticated = 0;
505     *complete = 0;
506
507     value->length = 0;
508     value->value = NULL;
509
510     if (display_value != NULL) {
511         display_value->length = 0;
512         display_value->value = NULL;
513     }
514
515     *more = -1;
516
517     if (name->attrCtx == NULL)
518         return GSS_S_UNAVAILABLE;
519
520     try {
521         if (!name->attrCtx->getAttribute(attr, authenticated, complete,
522                                          value, display_value, more))
523             return GSS_S_UNAVAILABLE;
524     } catch (std::exception &e) {
525         return mapException(minor, e);
526     }
527
528     return GSS_S_COMPLETE;
529 }
530
531 OM_uint32
532 gssEapDeleteNameAttribute(OM_uint32 *minor,
533                           gss_name_t name,
534                           gss_buffer_t attr)
535 {
536     if (name->attrCtx == NULL)
537         return GSS_S_UNAVAILABLE;
538
539     try {
540         name->attrCtx->deleteAttribute(attr);
541     } catch (std::exception &ex) {
542         return mapException(minor, ex);
543     }
544
545     return GSS_S_COMPLETE;
546 }
547
548 OM_uint32
549 gssEapSetNameAttribute(OM_uint32 *minor,
550                        gss_name_t name,
551                        int complete,
552                        gss_buffer_t attr,
553                        gss_buffer_t value)
554 {
555     if (name->attrCtx == NULL)
556         return GSS_S_UNAVAILABLE;
557
558     try {
559         name->attrCtx->setAttribute(complete, attr, value);
560     } catch (std::exception &ex) {
561         return mapException(minor, ex);
562     }
563
564     return GSS_S_COMPLETE;
565 }
566
567 OM_uint32
568 gssEapExportAttrContext(OM_uint32 *minor,
569                         gss_name_t name,
570                         gss_buffer_t buffer)
571 {
572     if (name->attrCtx == NULL) {
573         buffer->length = 0;
574         buffer->value = NULL;
575
576         return GSS_S_COMPLETE;
577     };
578
579     try {
580         name->attrCtx->exportToBuffer(buffer);
581     } catch (std::exception &e) {
582         return mapException(minor, e);
583     }
584
585     return GSS_S_COMPLETE;
586 }
587
588 OM_uint32
589 gssEapImportAttrContext(OM_uint32 *minor,
590                         gss_buffer_t buffer,
591                         gss_name_t name)
592 {
593     if (buffer->length != 0) {
594         gss_eap_attr_ctx *ctx = new gss_eap_attr_ctx;
595
596         try {
597             if (!ctx->initFromBuffer(NULL, buffer)) {
598                 delete ctx;
599                 return GSS_S_DEFECTIVE_TOKEN;
600             }
601             name->attrCtx = ctx;
602         } catch (std::exception &e) {
603             delete ctx;
604             return mapException(minor, e);
605         }
606     }
607
608     return GSS_S_COMPLETE;
609 }
610
611 OM_uint32
612 gssEapDuplicateAttrContext(OM_uint32 *minor,
613                            gss_name_t in,
614                            gss_name_t out)
615 {
616     gss_eap_attr_ctx *ctx = NULL;
617
618     assert(out->attrCtx == NULL);
619
620     try {
621         if (in->attrCtx != NULL) {
622             if (!ctx->initFromExistingContext(NULL, in->attrCtx)) {
623                 delete ctx;
624                 return GSS_S_FAILURE;
625             }
626             out->attrCtx = ctx;
627         }
628     } catch (std::exception &e) {
629         delete ctx;
630         return mapException(minor, e);
631     }
632
633     return GSS_S_COMPLETE;
634 }
635
636 OM_uint32
637 gssEapMapNameToAny(OM_uint32 *minor,
638                    gss_name_t name,
639                    int authenticated,
640                    gss_buffer_t type_id,
641                    gss_any_t *output)
642 {
643     try {
644         *output = name->attrCtx->mapToAny(authenticated, type_id);
645     } catch (std::exception &e) {
646         return mapException(minor, e);
647     }
648
649     return GSS_S_COMPLETE;
650 }
651
652 OM_uint32
653 gssEapReleaseAnyNameMapping(OM_uint32 *minor,
654                             gss_name_t name,
655                             gss_buffer_t type_id,
656                             gss_any_t *input)
657 {
658     if (name->attrCtx == NULL)
659         return GSS_S_UNAVAILABLE;
660
661     try {
662         if (*input != NULL)
663             name->attrCtx->releaseAnyNameMapping(type_id, *input);
664         *input = NULL;
665     } catch (std::exception &e) {
666         return mapException(minor, e);
667     }
668
669     return GSS_S_COMPLETE;
670 }
671
672 OM_uint32
673 gssEapReleaseAttrContext(OM_uint32 *minor,
674                          gss_name_t name)
675 {
676     if (name->attrCtx != NULL)
677         delete name->attrCtx;
678
679     return GSS_S_COMPLETE;
680 }
681
682 OM_uint32
683 gssEapAttrProvidersInit(OM_uint32 *minor)
684 {
685     try {
686         gss_eap_attr_ctx::init();
687     } catch (std::exception &e) {
688         return mapException(minor, e);
689     }
690
691     return GSS_S_COMPLETE;
692 }
693
694 OM_uint32
695 gssEapAttrProvidersFinalize(OM_uint32 *minor)
696 {
697     try {
698         gss_eap_attr_ctx::finalize();
699     } catch (std::exception &e) {
700         return mapException(minor, e);
701     }
702
703     return GSS_S_COMPLETE;
704 }
705
706 struct gss_eap_attr_ctx *
707 gssEapCreateAttrContext(gss_cred_id_t gssCred,
708                         gss_ctx_id_t gssCtx)
709 {
710     gss_eap_attr_ctx *ctx;
711
712     ctx = new gss_eap_attr_ctx;
713     if (!ctx->initFromGssContext(NULL, gssCred, gssCtx)) {
714         delete ctx;
715         return NULL;
716     }
717
718     return ctx;
719 }