cleanup
[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_factory
40 gss_eap_attr_factories[ATTR_TYPE_MAX] = {
41     gss_eap_radius_attr_source::createAttrContext,
42     gss_eap_saml_assertion_source::createAttrContext,
43     gss_eap_saml_attr_source::createAttrContext,
44     gss_eap_shib_attr_source::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_source *source;
51
52         source = (gss_eap_attr_factories[i])();
53
54         m_sources[i] = source;
55     }
56 }
57
58 bool
59 gss_eap_attr_ctx::initFromExistingContext(const gss_eap_attr_ctx *manager,
60                                           const gss_eap_attr_source *source)
61 {
62     if (!gss_eap_attr_source::initFromExistingContext(this, source))
63         return false;
64
65     for (unsigned int i = 0; i < ATTR_TYPE_MAX; i++) {
66         gss_eap_attr_source *source;
67
68         source = m_sources[i];
69         if (source != NULL) {
70             if (!source->initFromExistingContext(this, source))
71                 return false;
72         }
73     }
74
75     return true;
76 }
77
78 bool
79 gss_eap_attr_ctx::initFromGssContext(const gss_eap_attr_ctx *manager,
80                                      const gss_cred_id_t cred,
81                                      const gss_ctx_id_t ctx)
82 {
83     if (!gss_eap_attr_source::initFromGssContext(this, cred, ctx))
84         return false;
85
86     for (unsigned int i = 0; i < ATTR_TYPE_MAX; i++) {
87         gss_eap_attr_source *source;
88
89         source = m_sources[i];
90         if (source != NULL) {
91             if (!source->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_sources[i];
103 }
104
105 bool
106 gss_eap_attr_ctx::init(void)
107 {
108     return gss_eap_radius_attr_source::init() &&
109            gss_eap_saml_assertion_source::init() &&
110            gss_eap_saml_attr_source::init() &&
111            gss_eap_shib_attr_source::init();
112 }
113
114 void
115 gss_eap_attr_ctx::finalize(void)
116 {
117     gss_eap_shib_attr_source::finalize();
118     gss_eap_saml_attr_source::finalize();
119     gss_eap_saml_assertion_source::finalize();
120     gss_eap_radius_attr_source::finalize();
121 }
122
123 gss_eap_attr_source *
124 gss_eap_attr_ctx::getProvider(unsigned int type) const
125 {
126     return m_sources[type];
127 }
128
129 gss_eap_attr_source *
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_sources[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_source *source;
147
148     decomposeAttributeName(attr, &type, &suffix);
149
150     source = m_sources[type];
151     if (source != NULL) {
152         source->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_source *source;
165
166     decomposeAttributeName(attr, &type, &suffix);
167
168     source = m_sources[type];
169     if (source != NULL) {
170         source->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_source *source;
182
183         source = m_sources[i];
184         if (source == NULL)
185             continue;
186
187         ret = source->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_source *source,
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_source *source;
239
240         args.type = i;
241
242         source = m_sources[i];
243         if (source == NULL)
244             continue;
245
246         ret = source->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_source *source;
269     bool ret;
270
271     decomposeAttributeName(attr, &type, &suffix);
272
273     source = m_sources[type];
274     if (source == NULL) {
275         *more = 0;
276         return false;
277     }
278
279     ret = source->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_sources[ATTR_TYPE_RADIUS]->exportToBuffer(buffer);
303 }
304
305 bool
306 gss_eap_attr_ctx::initFromBuffer(const gss_eap_attr_ctx *manager,
307                                  const gss_buffer_t buffer)
308 {
309     unsigned int i;
310     bool ret;
311
312     ret = m_sources[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_source *source = m_sources[i];
318
319         ret = source->initFromGssContext(this,
320                                          GSS_C_NO_CREDENTIAL,
321                                          GSS_C_NO_CONTEXT);
322         if (!ret)
323             break;
324     }
325
326     return ret;
327 }
328
329
330 /*
331  * C wrappers
332  */
333
334 static OM_uint32
335 mapException(OM_uint32 *minor, std::exception &e)
336 {
337     *minor = 0;
338     return GSS_S_FAILURE;
339 }
340
341 static gss_buffer_desc attributePrefixes[] = {
342     {
343         /* ATTR_TYPE_RADIUS_AVP */
344         sizeof("urn:ietf:params:gss-eap:radius-avp"),
345         (void *)"urn:ietf:params:gss-eap:radius-avp",
346     },
347     {
348         /* ATTR_TYPE_SAML_AAA_ASSERTION */
349         sizeof("urn:ietf:params:gss-eap:saml-aaa-assertion"),
350         (void *)"urn:ietf:params:gss-eap:saml-aaa-assertion"
351     },
352     {
353         /* ATTR_TYPE_SAML_ATTR */
354         sizeof("urn:ietf:params:gss-eap:saml-attr"),
355         (void *)"urn:ietf:params:gss-eap:saml-attr"
356     },
357 };
358
359 unsigned int
360 gss_eap_attr_ctx::attributePrefixToType(const gss_buffer_t prefix)
361 {
362     unsigned int i;
363
364     for (i = ATTR_TYPE_MIN;
365          i < sizeof(attributePrefixes) / sizeof(attributePrefixes[0]);
366          i++)
367     {
368         if (bufferEqual(&attributePrefixes[i], prefix))
369             return i;
370     }
371
372     return ATTR_TYPE_LOCAL;
373 }
374
375 const gss_buffer_t
376 gss_eap_attr_ctx::attributeTypeToPrefix(unsigned int type)
377 {
378     if (type < ATTR_TYPE_MIN || type >= ATTR_TYPE_LOCAL)
379         return GSS_C_NO_BUFFER;
380
381     return &attributePrefixes[type];
382 }
383
384 void
385 gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
386                                          gss_buffer_t prefix,
387                                          gss_buffer_t suffix)
388 {
389     char *p = NULL;
390     size_t i;
391
392     for (i = 0; i < attribute->length; i++) {
393         if (((char *)attribute->value)[i] == ' ') {
394             p = (char *)attribute->value + i + 1;
395             break;
396         }
397     }
398
399     prefix->value = attribute->value;
400     prefix->length = i;
401
402     if (p != NULL && *p != '\0')  {
403         suffix->length = attribute->length - 1 - prefix->length;
404         suffix->value = p;
405     } else {
406         suffix->length = 0;
407         suffix->value = NULL;
408     }
409 }
410
411 std::string
412 gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
413                                        const gss_buffer_t suffix)
414 {
415     std::string str;
416
417     if (prefix == GSS_C_NO_BUFFER || prefix->length == 0)
418         return str;
419
420     str.append((const char *)prefix->value, prefix->length);
421
422     if (suffix != GSS_C_NO_BUFFER) {
423         str.append(" ");
424         str.append((const char *)suffix->value, suffix->length);
425     }
426
427     return str;
428 }
429
430 std::string
431 gss_eap_attr_ctx::composeAttributeName(unsigned int type,
432                                        const gss_buffer_t suffix)
433 {
434     const gss_buffer_t prefix = attributeTypeToPrefix(type);
435
436     return composeAttributeName(prefix, suffix);
437 }
438
439 void
440 gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
441                                        const gss_buffer_t suffix,
442                                        gss_buffer_t attribute)
443 {
444     std::string str = composeAttributeName(prefix, suffix);
445
446     if (str.length() != 0) {
447         return duplicateBuffer(str, attribute);
448     } else {
449         attribute->length = 0;
450         attribute->value = NULL;
451     }
452 }
453
454 void
455 gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
456                                          unsigned int *type,
457                                          gss_buffer_t suffix)
458 {
459     gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
460
461     decomposeAttributeName(attribute, &prefix, suffix);
462     *type = attributePrefixToType(&prefix);
463 }
464
465 void
466 gss_eap_attr_ctx::composeAttributeName(unsigned int type,
467                                        const gss_buffer_t suffix,
468                                        gss_buffer_t attribute)
469 {
470     gss_buffer_t prefix = attributeTypeToPrefix(type);
471
472     return composeAttributeName(prefix, suffix, attribute);
473 }
474
475 OM_uint32
476 gssEapInquireName(OM_uint32 *minor,
477                   gss_name_t name,
478                   int *name_is_MN,
479                   gss_OID *MN_mech,
480                   gss_buffer_set_t *attrs)
481 {
482     if (name->attrCtx == NULL)
483         return GSS_S_UNAVAILABLE;
484
485     try {
486         if (!name->attrCtx->getAttributeTypes(attrs))
487             return GSS_S_UNAVAILABLE;
488     } catch (std::exception &e) {
489         return mapException(minor, e);
490     }
491
492     return GSS_S_COMPLETE;
493 }
494
495 OM_uint32
496 gssEapGetNameAttribute(OM_uint32 *minor,
497                        gss_name_t name,
498                        gss_buffer_t attr,
499                        int *authenticated,
500                        int *complete,
501                        gss_buffer_t value,
502                        gss_buffer_t display_value,
503                        int *more)
504 {
505     *authenticated = 0;
506     *complete = 0;
507
508     value->length = 0;
509     value->value = NULL;
510
511     if (display_value != NULL) {
512         display_value->length = 0;
513         display_value->value = NULL;
514     }
515
516     *more = -1;
517
518     if (name->attrCtx == NULL)
519         return GSS_S_UNAVAILABLE;
520
521     try {
522         if (!name->attrCtx->getAttribute(attr, authenticated, complete,
523                                          value, display_value, more))
524             return GSS_S_UNAVAILABLE;
525     } catch (std::exception &e) {
526         return mapException(minor, e);
527     }
528
529     return GSS_S_COMPLETE;
530 }
531
532 OM_uint32
533 gssEapDeleteNameAttribute(OM_uint32 *minor,
534                           gss_name_t name,
535                           gss_buffer_t attr)
536 {
537     if (name->attrCtx == NULL)
538         return GSS_S_UNAVAILABLE;
539
540     try {
541         name->attrCtx->deleteAttribute(attr);
542     } catch (std::exception &ex) {
543         return mapException(minor, ex);
544     }
545
546     return GSS_S_COMPLETE;
547 }
548
549 OM_uint32
550 gssEapSetNameAttribute(OM_uint32 *minor,
551                        gss_name_t name,
552                        int complete,
553                        gss_buffer_t attr,
554                        gss_buffer_t value)
555 {
556     if (name->attrCtx == NULL)
557         return GSS_S_UNAVAILABLE;
558
559     try {
560         name->attrCtx->setAttribute(complete, attr, value);
561     } catch (std::exception &ex) {
562         return mapException(minor, ex);
563     }
564
565     return GSS_S_COMPLETE;
566 }
567
568 OM_uint32
569 gssEapExportAttrContext(OM_uint32 *minor,
570                         gss_name_t name,
571                         gss_buffer_t buffer)
572 {
573     if (name->attrCtx == NULL) {
574         buffer->length = 0;
575         buffer->value = NULL;
576
577         return GSS_S_COMPLETE;
578     };
579
580     try {
581         name->attrCtx->exportToBuffer(buffer);
582     } catch (std::exception &e) {
583         return mapException(minor, e);
584     }
585
586     return GSS_S_COMPLETE;
587 }
588
589 OM_uint32
590 gssEapImportAttrContext(OM_uint32 *minor,
591                         gss_buffer_t buffer,
592                         gss_name_t name)
593 {
594     gss_eap_attr_ctx *ctx = NULL;
595
596     assert(name->attrCtx == NULL);
597
598     if (buffer->length != 0) {
599         try {
600             ctx = new gss_eap_attr_ctx;
601
602             if (!ctx->initFromBuffer(NULL, buffer)) {
603                 delete ctx;
604                 return GSS_S_DEFECTIVE_TOKEN;
605             }
606             name->attrCtx = ctx;
607         } catch (std::exception &e) {
608             delete ctx;
609             return mapException(minor, e);
610         }
611     }
612
613     return GSS_S_COMPLETE;
614 }
615
616 OM_uint32
617 gssEapDuplicateAttrContext(OM_uint32 *minor,
618                            gss_name_t in,
619                            gss_name_t out)
620 {
621     gss_eap_attr_ctx *ctx = NULL;
622
623     assert(out->attrCtx == NULL);
624
625     try {
626         if (in->attrCtx != NULL) {
627             if (!ctx->initFromExistingContext(NULL, in->attrCtx)) {
628                 delete ctx;
629                 return GSS_S_FAILURE;
630             }
631             out->attrCtx = ctx;
632         }
633     } catch (std::exception &e) {
634         delete ctx;
635         return mapException(minor, e);
636     }
637
638     return GSS_S_COMPLETE;
639 }
640
641 OM_uint32
642 gssEapMapNameToAny(OM_uint32 *minor,
643                    gss_name_t name,
644                    int authenticated,
645                    gss_buffer_t type_id,
646                    gss_any_t *output)
647 {
648     try {
649         *output = name->attrCtx->mapToAny(authenticated, type_id);
650     } catch (std::exception &e) {
651         return mapException(minor, e);
652     }
653
654     return GSS_S_COMPLETE;
655 }
656
657 OM_uint32
658 gssEapReleaseAnyNameMapping(OM_uint32 *minor,
659                             gss_name_t name,
660                             gss_buffer_t type_id,
661                             gss_any_t *input)
662 {
663     if (name->attrCtx == NULL)
664         return GSS_S_UNAVAILABLE;
665
666     try {
667         if (*input != NULL)
668             name->attrCtx->releaseAnyNameMapping(type_id, *input);
669         *input = NULL;
670     } catch (std::exception &e) {
671         return mapException(minor, e);
672     }
673
674     return GSS_S_COMPLETE;
675 }
676
677 OM_uint32
678 gssEapReleaseAttrContext(OM_uint32 *minor,
679                          gss_name_t name)
680 {
681     if (name->attrCtx != NULL)
682         delete name->attrCtx;
683
684     return GSS_S_COMPLETE;
685 }
686
687 OM_uint32
688 gssEapAttrProvidersInit(OM_uint32 *minor)
689 {
690     try {
691         gss_eap_attr_ctx::init();
692     } catch (std::exception &e) {
693         return mapException(minor, e);
694     }
695
696     return GSS_S_COMPLETE;
697 }
698
699 OM_uint32
700 gssEapAttrProvidersFinalize(OM_uint32 *minor)
701 {
702     try {
703         gss_eap_attr_ctx::finalize();
704     } catch (std::exception &e) {
705         return mapException(minor, e);
706     }
707
708     return GSS_S_COMPLETE;
709 }
710
711 struct gss_eap_attr_ctx *
712 gssEapCreateAttrContext(gss_cred_id_t gssCred,
713                         gss_ctx_id_t gssCtx)
714 {
715     gss_eap_attr_ctx *ctx;
716
717     ctx = new gss_eap_attr_ctx;
718     if (!ctx->initFromGssContext(NULL, gssCred, gssCtx)) {
719         delete ctx;
720         return NULL;
721     }
722
723     return ctx;
724 }