Cleanup provider immediately if initialisation fails
[mech_eap.git] / 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 <typeinfo>
36 #include <string>
37 #include <exception>
38 #include <new>
39
40 static gss_eap_attr_create_provider gssEapAttrFactories[ATTR_TYPE_MAX + 1];
41 static gss_buffer_desc gssEapAttrPrefixes[ATTR_TYPE_MAX + 1];
42
43 /*
44  * Register a provider for a particular type and prefix
45  */
46 void
47 gss_eap_attr_ctx::registerProvider(unsigned int type,
48                                    const char *prefix,
49                                    gss_eap_attr_create_provider factory)
50 {
51     assert(type <= ATTR_TYPE_MAX);
52
53     assert(gssEapAttrFactories[type] == NULL);
54
55     gssEapAttrFactories[type] = factory;
56     if (prefix != NULL) {
57         gssEapAttrPrefixes[type].value = (void *)prefix;
58         gssEapAttrPrefixes[type].length = strlen(prefix);
59     } else {
60         gssEapAttrPrefixes[type].value = NULL;
61         gssEapAttrPrefixes[type].length = 0;
62     }
63 }
64
65 /*
66  * Unregister a provider
67  */
68 void
69 gss_eap_attr_ctx::unregisterProvider(unsigned int type)
70 {
71     assert(type <= ATTR_TYPE_MAX);
72
73     gssEapAttrFactories[type] = NULL;
74     gssEapAttrPrefixes[type].value = NULL;
75     gssEapAttrPrefixes[type].length = 0;
76 }
77
78 /*
79  * Create an attribute context, that manages instances of providers
80  */
81 gss_eap_attr_ctx::gss_eap_attr_ctx(void)
82 {
83     for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
84         gss_eap_attr_provider *provider;
85
86         if (gssEapAttrFactories[i] != NULL) {
87             provider = (gssEapAttrFactories[i])();
88         } else {
89             provider = NULL;
90         }
91
92         m_providers[i] = provider;
93     }
94 }
95
96 /*
97  * Convert an attribute prefix to a type
98  */
99 unsigned int
100 gss_eap_attr_ctx::attributePrefixToType(const gss_buffer_t prefix)
101 {
102     unsigned int i;
103
104     for (i = ATTR_TYPE_MIN; i < ATTR_TYPE_MAX; i++) {
105         if (bufferEqual(&gssEapAttrPrefixes[i], prefix))
106             return i;
107     }
108
109     return ATTR_TYPE_LOCAL;
110 }
111
112 /*
113  * Convert a type to an attribute prefix
114  */
115 const gss_buffer_t
116 gss_eap_attr_ctx::attributeTypeToPrefix(unsigned int type)
117 {
118     if (type < ATTR_TYPE_MIN || type >= ATTR_TYPE_MAX)
119         return GSS_C_NO_BUFFER;
120
121     return &gssEapAttrPrefixes[type];
122 }
123
124 /*
125  * Initialize a context from an existing context.
126  */
127 bool
128 gss_eap_attr_ctx::initFromExistingContext(const gss_eap_attr_ctx *manager)
129 {
130     bool ret = true;
131
132     for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
133         gss_eap_attr_provider *provider = m_providers[i];
134
135         if (provider == NULL)
136             continue;
137
138         ret = provider->initFromExistingContext(this,
139                                                 manager->m_providers[i]);
140         if (ret == false) {
141             delete provider;
142             m_providers[i] = NULL;
143             break;
144         }
145     }
146
147     return ret;
148 }
149
150 /*
151  * Initialize a context from a GSS credential and context.
152  */
153 bool
154 gss_eap_attr_ctx::initFromGssContext(const gss_cred_id_t cred,
155                                      const gss_ctx_id_t ctx)
156 {
157     bool ret = true;
158
159     for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
160         gss_eap_attr_provider *provider = m_providers[i];
161
162         if (provider == NULL)
163             continue;
164
165         ret = provider->initFromGssContext(this, cred, ctx);
166         if (ret == false) {
167             delete provider;
168             m_providers[i] = NULL;
169             break;
170         }
171     }
172
173     return ret;
174 }
175
176 /*
177  * Initialize a context from an exported context or name token
178  */
179 bool
180 gss_eap_attr_ctx::initFromBuffer(const gss_buffer_t buffer)
181 {
182     bool ret;
183     gss_eap_attr_provider *primaryProvider = getPrimaryProvider();
184
185     ret = primaryProvider->initFromBuffer(this, buffer);
186     if (ret == false)
187         return ret;
188
189     for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
190         gss_eap_attr_provider *provider = m_providers[i];
191
192         if (provider == primaryProvider)
193             continue;
194
195         ret = provider->initFromGssContext(this,
196                                            GSS_C_NO_CREDENTIAL,
197                                            GSS_C_NO_CONTEXT);
198         if (ret == false) {
199             delete provider;
200             m_providers[i] = NULL;
201             break;
202         }
203     }
204
205     return ret;
206 }
207
208 gss_eap_attr_ctx::~gss_eap_attr_ctx(void)
209 {
210     for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++)
211         delete m_providers[i];
212 }
213
214 /*
215  * Locate provider for a given type
216  */
217 gss_eap_attr_provider *
218 gss_eap_attr_ctx::getProvider(unsigned int type) const
219 {
220     assert(type >= ATTR_TYPE_MIN && type <= ATTR_TYPE_MAX);
221     return m_providers[type];
222 }
223
224 /*
225  * Locate provider for a given prefix
226  */
227 gss_eap_attr_provider *
228 gss_eap_attr_ctx::getProvider(const gss_buffer_t prefix) const
229 {
230     unsigned int type;
231
232     type = attributePrefixToType(prefix);
233
234     return m_providers[type];
235 }
236
237 /*
238  * Get primary provider. Only the primary provider is serialised when
239  * gss_export_sec_context() or gss_export_name_composite() is called.
240  */
241 gss_eap_attr_provider *
242 gss_eap_attr_ctx::getPrimaryProvider(void) const
243 {
244     return m_providers[ATTR_TYPE_MIN];
245 }
246
247 /*
248  * Set an attribute
249  */
250 void
251 gss_eap_attr_ctx::setAttribute(int complete,
252                                const gss_buffer_t attr,
253                                const gss_buffer_t value)
254 {
255     gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
256     unsigned int type;
257     gss_eap_attr_provider *provider;
258
259     decomposeAttributeName(attr, &type, &suffix);
260
261     provider = m_providers[type];
262     if (provider != NULL) {
263         provider->setAttribute(complete,
264                                (type == ATTR_TYPE_LOCAL) ? attr : &suffix,
265                                value);
266     } else {
267         /* XXX TODO throw exception */
268     }
269 }
270
271 /*
272  * Delete an attrbiute
273  */
274 void
275 gss_eap_attr_ctx::deleteAttribute(const gss_buffer_t attr)
276 {
277     gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
278     unsigned int type;
279     gss_eap_attr_provider *provider;
280
281     decomposeAttributeName(attr, &type, &suffix);
282
283     provider = m_providers[type];
284     if (provider != NULL)
285         provider->deleteAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix);
286 }
287
288 /*
289  * Enumerate attribute types with callback
290  */
291 bool
292 gss_eap_attr_ctx::getAttributeTypes(gss_eap_attr_enumeration_cb cb, void *data) const
293 {
294     bool ret = false;
295     size_t i;
296
297     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
298         gss_eap_attr_provider *provider = m_providers[i];
299
300         if (provider == NULL)
301             continue;
302
303         ret = provider->getAttributeTypes(cb, data);
304         if (ret == false)
305             break;
306     }
307
308     return ret;
309 }
310
311 struct eap_gss_get_attr_types_args {
312     unsigned int type;
313     gss_buffer_set_t attrs;
314 };
315
316 static bool
317 addAttribute(const gss_eap_attr_provider *provider,
318              const gss_buffer_t attribute,
319              void *data)
320 {
321     eap_gss_get_attr_types_args *args = (eap_gss_get_attr_types_args *)data;
322     gss_buffer_desc qualified;
323     OM_uint32 major, minor;
324
325     if (args->type != ATTR_TYPE_LOCAL) {
326         gss_eap_attr_ctx::composeAttributeName(args->type, attribute, &qualified);
327         major = gss_add_buffer_set_member(&minor, &qualified, &args->attrs);
328         gss_release_buffer(&minor, &qualified);
329     } else {
330         major = gss_add_buffer_set_member(&minor, attribute, &args->attrs);
331     }
332
333     return GSS_ERROR(major) == false;
334 }
335
336 /*
337  * Enumerate attribute types, output is buffer set
338  */
339 bool
340 gss_eap_attr_ctx::getAttributeTypes(gss_buffer_set_t *attrs)
341 {
342     eap_gss_get_attr_types_args args;
343     OM_uint32 major, minor;
344     bool ret = false;
345     unsigned int i;
346
347     major = gss_create_empty_buffer_set(&minor, attrs);
348     if (GSS_ERROR(major)) {
349         throw new std::bad_alloc;
350         return false;
351     }
352
353     args.attrs = *attrs;
354
355     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
356         gss_eap_attr_provider *provider = m_providers[i];
357
358         args.type = i;
359
360         if (provider == NULL)
361             continue;
362
363         ret = provider->getAttributeTypes(addAttribute, (void *)&args);
364         if (ret == false)
365             break;
366     }
367
368     if (ret == false)
369         gss_release_buffer_set(&minor, attrs);
370
371     return ret;
372 }
373
374 /*
375  * Get attribute with given name
376  */
377 bool
378 gss_eap_attr_ctx::getAttribute(const gss_buffer_t attr,
379                                int *authenticated,
380                                int *complete,
381                                gss_buffer_t value,
382                                gss_buffer_t display_value,
383                                int *more) const
384 {
385     gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
386     unsigned int type;
387     gss_eap_attr_provider *provider;
388     bool ret;
389
390     decomposeAttributeName(attr, &type, &suffix);
391
392     provider = m_providers[type];
393     if (provider == NULL)
394         return false;
395
396     ret = provider->getAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix,
397                                  authenticated, complete,
398                                  value, display_value, more);
399
400     return ret;
401 }
402
403 /*
404  * Map attribute context to C++ object
405  */
406 gss_any_t
407 gss_eap_attr_ctx::mapToAny(int authenticated,
408                            gss_buffer_t type_id) const
409 {
410     unsigned int type;
411     gss_eap_attr_provider *provider;
412     gss_buffer_desc suffix;
413
414     decomposeAttributeName(type_id, &type, &suffix);
415
416     provider = m_providers[type];
417     if (provider == NULL)
418         return (gss_any_t)NULL;
419
420     return provider->mapToAny(authenticated, &suffix);
421 }
422
423 /*
424  * Release mapped context
425  */
426 void
427 gss_eap_attr_ctx::releaseAnyNameMapping(gss_buffer_t type_id,
428                                         gss_any_t input) const
429 {
430     unsigned int type;
431     gss_eap_attr_provider *provider;
432     gss_buffer_desc suffix;
433
434     decomposeAttributeName(type_id, &type, &suffix);
435
436     provider = m_providers[type];
437     if (provider != NULL)
438         provider->releaseAnyNameMapping(&suffix, input);
439 }
440
441 /*
442  * Export attribute context to buffer
443  */
444 void
445 gss_eap_attr_ctx::exportToBuffer(gss_buffer_t buffer) const
446 {
447     getPrimaryProvider()->exportToBuffer(buffer);
448 }
449
450 /*
451  * Return soonest expiry time of providers
452  */
453 time_t
454 gss_eap_attr_ctx::getExpiryTime(void) const
455 {
456     unsigned int i;
457     time_t expiryTime = 0;
458
459     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
460         gss_eap_attr_provider *provider = m_providers[i];
461         time_t providerExpiryTime;
462
463         if (provider == NULL)
464             continue;
465
466         providerExpiryTime = provider->getExpiryTime();
467         if (providerExpiryTime == 0)
468             continue;
469
470         if (expiryTime == 0 || providerExpiryTime < expiryTime)
471             expiryTime = providerExpiryTime;
472     }
473
474     return expiryTime;
475 }
476
477 /*
478  * Map C++ exception to GSS status
479  */
480 static OM_uint32
481 mapException(OM_uint32 *minor, std::exception &e)
482 {
483     OM_uint32 major = GSS_S_FAILURE;
484
485     /* XXX TODO implement other mappings */
486     if (typeid(e) == typeid(std::bad_alloc))
487         *minor = ENOMEM;
488     else
489         *minor = 0;
490
491 #ifdef GSSEAP_DEBUG
492     /* rethrow for now for debugging */
493     throw e;
494 #endif
495
496     return major;
497 }
498
499 /*
500  * Decompose attribute name into prefix and suffix
501  */
502 void
503 gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
504                                          gss_buffer_t prefix,
505                                          gss_buffer_t suffix)
506 {
507     char *p = NULL;
508     size_t i;
509
510     for (i = 0; i < attribute->length; i++) {
511         if (((char *)attribute->value)[i] == ' ') {
512             p = (char *)attribute->value + i + 1;
513             break;
514         }
515     }
516
517     prefix->value = attribute->value;
518     prefix->length = i;
519
520     if (p != NULL && *p != '\0')  {
521         suffix->length = attribute->length - 1 - prefix->length;
522         suffix->value = p;
523     } else {
524         suffix->length = 0;
525         suffix->value = NULL;
526     }
527 }
528
529 /*
530  * Decompose attribute name into type and suffix
531  */
532 void
533 gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
534                                          unsigned int *type,
535                                          gss_buffer_t suffix)
536 {
537     gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
538
539     decomposeAttributeName(attribute, &prefix, suffix);
540     *type = attributePrefixToType(&prefix);
541 }
542
543 /*
544  * Compose attribute name from prefix, suffix; returns C++ string
545  */
546 std::string
547 gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
548                                        const gss_buffer_t suffix)
549 {
550     std::string str;
551
552     if (prefix == GSS_C_NO_BUFFER || prefix->length == 0)
553         return str;
554
555     str.append((const char *)prefix->value, prefix->length);
556
557     if (suffix != GSS_C_NO_BUFFER) {
558         str.append(" ");
559         str.append((const char *)suffix->value, suffix->length);
560     }
561
562     return str;
563 }
564
565 /*
566  * Compose attribute name from type, suffix; returns C++ string
567  */
568 std::string
569 gss_eap_attr_ctx::composeAttributeName(unsigned int type,
570                                        const gss_buffer_t suffix)
571 {
572     const gss_buffer_t prefix = attributeTypeToPrefix(type);
573
574     return composeAttributeName(prefix, suffix);
575 }
576
577 /*
578  * Compose attribute name from prefix, suffix; returns GSS buffer
579  */
580 void
581 gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
582                                        const gss_buffer_t suffix,
583                                        gss_buffer_t attribute)
584 {
585     std::string str = composeAttributeName(prefix, suffix);
586
587     if (str.length() != 0) {
588         return duplicateBuffer(str, attribute);
589     } else {
590         attribute->length = 0;
591         attribute->value = NULL;
592     }
593 }
594
595 /*
596  * Compose attribute name from type, suffix; returns GSS buffer
597  */
598 void
599 gss_eap_attr_ctx::composeAttributeName(unsigned int type,
600                                        const gss_buffer_t suffix,
601                                        gss_buffer_t attribute)
602 {
603     gss_buffer_t prefix = attributeTypeToPrefix(type);
604
605     return composeAttributeName(prefix, suffix, attribute);
606 }
607
608 /*
609  * C wrappers
610  */
611 OM_uint32
612 gssEapInquireName(OM_uint32 *minor,
613                   gss_name_t name,
614                   int *name_is_MN,
615                   gss_OID *MN_mech,
616                   gss_buffer_set_t *attrs)
617 {
618     if (name->attrCtx == NULL)
619         return GSS_S_UNAVAILABLE;
620
621     try {
622         if (!name->attrCtx->getAttributeTypes(attrs))
623             return GSS_S_UNAVAILABLE;
624     } catch (std::exception &e) {
625         return mapException(minor, e);
626     }
627
628     return GSS_S_COMPLETE;
629 }
630
631 OM_uint32
632 gssEapGetNameAttribute(OM_uint32 *minor,
633                        gss_name_t name,
634                        gss_buffer_t attr,
635                        int *authenticated,
636                        int *complete,
637                        gss_buffer_t value,
638                        gss_buffer_t display_value,
639                        int *more)
640 {
641     *authenticated = 0;
642     *complete = 0;
643
644     if (value != NULL) {
645         value->length = 0;
646         value->value = NULL;
647     }
648
649     if (display_value != NULL) {
650         display_value->length = 0;
651         display_value->value = NULL;
652     }
653
654     if (name->attrCtx == NULL)
655         return GSS_S_UNAVAILABLE;
656
657     try {
658         if (!name->attrCtx->getAttribute(attr, authenticated, complete,
659                                          value, display_value, more))
660             return GSS_S_UNAVAILABLE;
661     } catch (std::exception &e) {
662         return mapException(minor, e);
663     }
664
665     return GSS_S_COMPLETE;
666 }
667
668 OM_uint32
669 gssEapDeleteNameAttribute(OM_uint32 *minor,
670                           gss_name_t name,
671                           gss_buffer_t attr)
672 {
673     if (name->attrCtx == NULL)
674         return GSS_S_UNAVAILABLE;
675
676     try {
677         name->attrCtx->deleteAttribute(attr);
678     } catch (std::exception &ex) {
679         return mapException(minor, ex);
680     }
681
682     return GSS_S_COMPLETE;
683 }
684
685 OM_uint32
686 gssEapSetNameAttribute(OM_uint32 *minor,
687                        gss_name_t name,
688                        int complete,
689                        gss_buffer_t attr,
690                        gss_buffer_t value)
691 {
692     if (name->attrCtx == NULL)
693         return GSS_S_UNAVAILABLE;
694
695     try {
696         name->attrCtx->setAttribute(complete, attr, value);
697     } catch (std::exception &ex) {
698         return mapException(minor, ex);
699     }
700
701     return GSS_S_COMPLETE;
702 }
703
704 OM_uint32
705 gssEapExportAttrContext(OM_uint32 *minor,
706                         gss_name_t name,
707                         gss_buffer_t buffer)
708 {
709     if (name->attrCtx == NULL) {
710         buffer->length = 0;
711         buffer->value = NULL;
712
713         return GSS_S_COMPLETE;
714     }
715
716     try {
717         name->attrCtx->exportToBuffer(buffer);
718     } catch (std::exception &e) {
719         return mapException(minor, e);
720     }
721
722     return GSS_S_COMPLETE;
723 }
724
725 OM_uint32
726 gssEapImportAttrContext(OM_uint32 *minor,
727                         gss_buffer_t buffer,
728                         gss_name_t name)
729 {
730     gss_eap_attr_ctx *ctx = NULL;
731
732     assert(name->attrCtx == NULL);
733
734     if (buffer->length != 0) {
735         try {
736             ctx = new gss_eap_attr_ctx();
737
738             if (!ctx->initFromBuffer(buffer)) {
739                 delete ctx;
740                 return GSS_S_DEFECTIVE_TOKEN;
741             }
742             name->attrCtx = ctx;
743         } catch (std::exception &e) {
744             delete ctx;
745             return mapException(minor, e);
746         }
747     }
748
749     return GSS_S_COMPLETE;
750 }
751
752 OM_uint32
753 gssEapDuplicateAttrContext(OM_uint32 *minor,
754                            gss_name_t in,
755                            gss_name_t out)
756 {
757     gss_eap_attr_ctx *ctx = NULL;
758
759     assert(out->attrCtx == NULL);
760
761     try {
762         if (in->attrCtx != NULL) {
763             ctx = new gss_eap_attr_ctx();
764             if (!ctx->initFromExistingContext(in->attrCtx)) {
765                 delete ctx;
766                 return GSS_S_FAILURE;
767             }
768             out->attrCtx = ctx;
769         }
770     } catch (std::exception &e) {
771         delete ctx;
772         return mapException(minor, e);
773     }
774
775     return GSS_S_COMPLETE;
776 }
777
778 OM_uint32
779 gssEapMapNameToAny(OM_uint32 *minor,
780                    gss_name_t name,
781                    int authenticated,
782                    gss_buffer_t type_id,
783                    gss_any_t *output)
784 {
785     if (name->attrCtx == NULL)
786         return GSS_S_UNAVAILABLE;
787
788     try {
789         *output = name->attrCtx->mapToAny(authenticated, type_id);
790     } catch (std::exception &e) {
791         return mapException(minor, e);
792     }
793
794     return GSS_S_COMPLETE;
795 }
796
797 OM_uint32
798 gssEapReleaseAnyNameMapping(OM_uint32 *minor,
799                             gss_name_t name,
800                             gss_buffer_t type_id,
801                             gss_any_t *input)
802 {
803     if (name->attrCtx == NULL)
804         return GSS_S_UNAVAILABLE;
805
806     try {
807         if (*input != NULL)
808             name->attrCtx->releaseAnyNameMapping(type_id, *input);
809         *input = NULL;
810     } catch (std::exception &e) {
811         return mapException(minor, e);
812     }
813
814     return GSS_S_COMPLETE;
815 }
816
817 OM_uint32
818 gssEapReleaseAttrContext(OM_uint32 *minor,
819                          gss_name_t name)
820 {
821     if (name->attrCtx != NULL)
822         delete name->attrCtx;
823
824     return GSS_S_COMPLETE;
825 }
826
827 /*
828  * Public accessor for initialisng a context from a GSS context. Also
829  * sets expiry time on GSS context as a side-effect.
830  */
831 struct gss_eap_attr_ctx *
832 gssEapCreateAttrContext(gss_cred_id_t gssCred,
833                         gss_ctx_id_t gssCtx)
834 {
835     gss_eap_attr_ctx *ctx;
836
837     assert(gssCtx != GSS_C_NO_CONTEXT);
838
839     ctx = new gss_eap_attr_ctx();
840     if (!ctx->initFromGssContext(gssCred, gssCtx)) {
841         delete ctx;
842         return NULL;
843     }
844
845     gssCtx->expiryTime = ctx->getExpiryTime();
846
847     return ctx;
848 }