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