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