f862f6e124d4d8ffb6fff7f5f6f491d66e78318f
[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 <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     const gss_eap_attr_provider *primaryProvider = getPrimaryProvider();
448
449     primaryProvider->exportToBuffer(buffer);
450 }
451
452 /*
453  * Return soonest expiry time of providers
454  */
455 time_t
456 gss_eap_attr_ctx::getExpiryTime(void) const
457 {
458     unsigned int i;
459     time_t expiryTime = 0;
460
461     for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
462         gss_eap_attr_provider *provider = m_providers[i];
463         time_t providerExpiryTime;
464
465         if (provider == NULL)
466             continue;
467
468         providerExpiryTime = provider->getExpiryTime();
469         if (providerExpiryTime == 0)
470             continue;
471
472         if (expiryTime == 0 || providerExpiryTime < expiryTime)
473             expiryTime = providerExpiryTime;
474     }
475
476     return expiryTime;
477 }
478
479 /*
480  * Map C++ exception to GSS status
481  */
482 static OM_uint32
483 mapException(OM_uint32 *minor, std::exception &e)
484 {
485     OM_uint32 major = GSS_S_FAILURE;
486
487     /* XXX TODO implement other mappings */
488     if (typeid(e) == typeid(std::bad_alloc))
489         *minor = ENOMEM;
490     else
491         *minor = 0;
492
493 #ifdef GSSEAP_DEBUG
494     /* rethrow for now for debugging */
495     throw e;
496 #endif
497
498     return major;
499 }
500
501 /*
502  * Decompose attribute name into prefix and suffix
503  */
504 void
505 gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
506                                          gss_buffer_t prefix,
507                                          gss_buffer_t suffix)
508 {
509     char *p = NULL;
510     size_t i;
511
512     for (i = 0; i < attribute->length; i++) {
513         if (((char *)attribute->value)[i] == ' ') {
514             p = (char *)attribute->value + i + 1;
515             break;
516         }
517     }
518
519     prefix->value = attribute->value;
520     prefix->length = i;
521
522     if (p != NULL && *p != '\0')  {
523         suffix->length = attribute->length - 1 - prefix->length;
524         suffix->value = p;
525     } else {
526         suffix->length = 0;
527         suffix->value = NULL;
528     }
529 }
530
531 /*
532  * Decompose attribute name into type and suffix
533  */
534 void
535 gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
536                                          unsigned int *type,
537                                          gss_buffer_t suffix)
538 {
539     gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
540
541     decomposeAttributeName(attribute, &prefix, suffix);
542     *type = attributePrefixToType(&prefix);
543 }
544
545 /*
546  * Compose attribute name from prefix, suffix; returns C++ string
547  */
548 std::string
549 gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
550                                        const gss_buffer_t suffix)
551 {
552     std::string str;
553
554     if (prefix == GSS_C_NO_BUFFER || prefix->length == 0)
555         return str;
556
557     str.append((const char *)prefix->value, prefix->length);
558
559     if (suffix != GSS_C_NO_BUFFER) {
560         str.append(" ");
561         str.append((const char *)suffix->value, suffix->length);
562     }
563
564     return str;
565 }
566
567 /*
568  * Compose attribute name from type, suffix; returns C++ string
569  */
570 std::string
571 gss_eap_attr_ctx::composeAttributeName(unsigned int type,
572                                        const gss_buffer_t suffix)
573 {
574     const gss_buffer_t prefix = attributeTypeToPrefix(type);
575
576     return composeAttributeName(prefix, suffix);
577 }
578
579 /*
580  * Compose attribute name from prefix, suffix; returns GSS buffer
581  */
582 void
583 gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
584                                        const gss_buffer_t suffix,
585                                        gss_buffer_t attribute)
586 {
587     std::string str = composeAttributeName(prefix, suffix);
588
589     if (str.length() != 0) {
590         return duplicateBuffer(str, attribute);
591     } else {
592         attribute->length = 0;
593         attribute->value = NULL;
594     }
595 }
596
597 /*
598  * Compose attribute name from type, suffix; returns GSS buffer
599  */
600 void
601 gss_eap_attr_ctx::composeAttributeName(unsigned int type,
602                                        const gss_buffer_t suffix,
603                                        gss_buffer_t attribute)
604 {
605     gss_buffer_t prefix = attributeTypeToPrefix(type);
606
607     return composeAttributeName(prefix, suffix, attribute);
608 }
609
610 /*
611  * C wrappers
612  */
613 OM_uint32
614 gssEapInquireName(OM_uint32 *minor,
615                   gss_name_t name,
616                   int *name_is_MN,
617                   gss_OID *MN_mech,
618                   gss_buffer_set_t *attrs)
619 {
620     if (name->attrCtx == NULL)
621         return GSS_S_UNAVAILABLE;
622
623     try {
624         if (!name->attrCtx->getAttributeTypes(attrs))
625             return GSS_S_UNAVAILABLE;
626     } catch (std::exception &e) {
627         return mapException(minor, e);
628     }
629
630     return GSS_S_COMPLETE;
631 }
632
633 OM_uint32
634 gssEapGetNameAttribute(OM_uint32 *minor,
635                        gss_name_t name,
636                        gss_buffer_t attr,
637                        int *authenticated,
638                        int *complete,
639                        gss_buffer_t value,
640                        gss_buffer_t display_value,
641                        int *more)
642 {
643     *authenticated = 0;
644     *complete = 0;
645
646     if (value != NULL) {
647         value->length = 0;
648         value->value = NULL;
649     }
650
651     if (display_value != NULL) {
652         display_value->length = 0;
653         display_value->value = NULL;
654     }
655
656     if (name->attrCtx == NULL)
657         return GSS_S_UNAVAILABLE;
658
659     try {
660         if (!name->attrCtx->getAttribute(attr, authenticated, complete,
661                                          value, display_value, more))
662             return GSS_S_UNAVAILABLE;
663     } catch (std::exception &e) {
664         return mapException(minor, e);
665     }
666
667     return GSS_S_COMPLETE;
668 }
669
670 OM_uint32
671 gssEapDeleteNameAttribute(OM_uint32 *minor,
672                           gss_name_t name,
673                           gss_buffer_t attr)
674 {
675     if (name->attrCtx == NULL)
676         return GSS_S_UNAVAILABLE;
677
678     try {
679         name->attrCtx->deleteAttribute(attr);
680     } catch (std::exception &ex) {
681         return mapException(minor, ex);
682     }
683
684     return GSS_S_COMPLETE;
685 }
686
687 OM_uint32
688 gssEapSetNameAttribute(OM_uint32 *minor,
689                        gss_name_t name,
690                        int complete,
691                        gss_buffer_t attr,
692                        gss_buffer_t value)
693 {
694     if (name->attrCtx == NULL)
695         return GSS_S_UNAVAILABLE;
696
697     try {
698         name->attrCtx->setAttribute(complete, attr, value);
699     } catch (std::exception &ex) {
700         return mapException(minor, ex);
701     }
702
703     return GSS_S_COMPLETE;
704 }
705
706 OM_uint32
707 gssEapExportAttrContext(OM_uint32 *minor,
708                         gss_name_t name,
709                         gss_buffer_t buffer)
710 {
711     if (name->attrCtx == NULL) {
712         buffer->length = 0;
713         buffer->value = NULL;
714
715         return GSS_S_COMPLETE;
716     }
717
718     try {
719         name->attrCtx->exportToBuffer(buffer);
720     } catch (std::exception &e) {
721         return mapException(minor, e);
722     }
723
724     return GSS_S_COMPLETE;
725 }
726
727 OM_uint32
728 gssEapImportAttrContext(OM_uint32 *minor,
729                         gss_buffer_t buffer,
730                         gss_name_t name)
731 {
732     gss_eap_attr_ctx *ctx = NULL;
733
734     assert(name->attrCtx == NULL);
735
736     if (buffer->length != 0) {
737         try {
738             ctx = new gss_eap_attr_ctx();
739
740             if (!ctx->initFromBuffer(buffer)) {
741                 delete ctx;
742                 return GSS_S_DEFECTIVE_TOKEN;
743             }
744             name->attrCtx = ctx;
745         } catch (std::exception &e) {
746             delete ctx;
747             return mapException(minor, e);
748         }
749     }
750
751     return GSS_S_COMPLETE;
752 }
753
754 OM_uint32
755 gssEapDuplicateAttrContext(OM_uint32 *minor,
756                            gss_name_t in,
757                            gss_name_t out)
758 {
759     gss_eap_attr_ctx *ctx = NULL;
760
761     assert(out->attrCtx == NULL);
762
763     try {
764         if (in->attrCtx != NULL) {
765             ctx = new gss_eap_attr_ctx();
766             if (!ctx->initFromExistingContext(in->attrCtx)) {
767                 delete ctx;
768                 return GSS_S_FAILURE;
769             }
770             out->attrCtx = ctx;
771         }
772     } catch (std::exception &e) {
773         delete ctx;
774         return mapException(minor, e);
775     }
776
777     return GSS_S_COMPLETE;
778 }
779
780 OM_uint32
781 gssEapMapNameToAny(OM_uint32 *minor,
782                    gss_name_t name,
783                    int authenticated,
784                    gss_buffer_t type_id,
785                    gss_any_t *output)
786 {
787     if (name->attrCtx == NULL)
788         return GSS_S_UNAVAILABLE;
789
790     try {
791         *output = name->attrCtx->mapToAny(authenticated, type_id);
792     } catch (std::exception &e) {
793         return mapException(minor, e);
794     }
795
796     return GSS_S_COMPLETE;
797 }
798
799 OM_uint32
800 gssEapReleaseAnyNameMapping(OM_uint32 *minor,
801                             gss_name_t name,
802                             gss_buffer_t type_id,
803                             gss_any_t *input)
804 {
805     if (name->attrCtx == NULL)
806         return GSS_S_UNAVAILABLE;
807
808     try {
809         if (*input != NULL)
810             name->attrCtx->releaseAnyNameMapping(type_id, *input);
811         *input = NULL;
812     } catch (std::exception &e) {
813         return mapException(minor, e);
814     }
815
816     return GSS_S_COMPLETE;
817 }
818
819 OM_uint32
820 gssEapReleaseAttrContext(OM_uint32 *minor,
821                          gss_name_t name)
822 {
823     if (name->attrCtx != NULL)
824         delete name->attrCtx;
825
826     return GSS_S_COMPLETE;
827 }
828
829 /*
830  * Public accessor for initialisng a context from a GSS context. Also
831  * sets expiry time on GSS context as a side-effect.
832  */
833 struct gss_eap_attr_ctx *
834 gssEapCreateAttrContext(gss_cred_id_t gssCred,
835                         gss_ctx_id_t gssCtx)
836 {
837     gss_eap_attr_ctx *ctx;
838
839     assert(gssCtx != GSS_C_NO_CONTEXT);
840
841     ctx = new gss_eap_attr_ctx();
842     if (!ctx->initFromGssContext(gssCred, gssCtx)) {
843         delete ctx;
844         return NULL;
845     }
846
847     gssCtx->expiryTime = ctx->getExpiryTime();
848
849     return ctx;
850 }