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