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