make reauth support conditionaly compilable
[mech_eap.git] / accept_sec_context.c
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 #ifdef GSSEAP_ENABLE_REAUTH
36 static OM_uint32
37 eapGssSmAcceptGssReauth(OM_uint32 *minor,
38                         gss_ctx_id_t ctx,
39                         gss_cred_id_t cred,
40                         gss_buffer_t inputToken,
41                         gss_channel_bindings_t chanBindings,
42                         gss_buffer_t outputToken);
43 #endif
44
45 /*
46  * Mark a context as ready for cryptographic operations
47  */
48 static OM_uint32
49 acceptReadyEap(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred)
50 {
51     OM_uint32 major, tmpMinor;
52     VALUE_PAIR *vp;
53     gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
54
55     /* Cache encryption type derived from selected mechanism OID */
56     major = gssEapOidToEnctype(minor, ctx->mechanismUsed,
57                                &ctx->encryptionType);
58     if (GSS_ERROR(major))
59         return major;
60
61     gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
62
63     vp = rc_avpair_get(ctx->acceptorCtx.avps, PW_USER_NAME, 0);
64     if (vp != NULL) {
65         nameBuf.length = vp->lvalue;
66         nameBuf.value = vp->strvalue;
67     } else {
68         ctx->gssFlags |= GSS_C_ANON_FLAG;
69     }
70
71     major = gssEapImportName(minor, &nameBuf, GSS_C_NT_USER_NAME,
72                              &ctx->initiatorName);
73     if (GSS_ERROR(major))
74         return major;
75
76     ctx->initiatorName->attrCtx = gssEapCreateAttrContext(cred, ctx);
77
78     vp = rc_avpair_get(ctx->acceptorCtx.avps,
79                        VENDOR_ATTR_MS_MPPE_SEND_KEY,
80                        VENDOR_ID_MICROSOFT);
81     if (ctx->encryptionType != ENCTYPE_NULL && vp != NULL) {
82         major = gssEapDeriveRfc3961Key(minor,
83                                        (unsigned char *)vp->strvalue,
84                                        vp->lvalue,
85                                        ctx->encryptionType,
86                                        &ctx->rfc3961Key);
87         if (GSS_ERROR(major))
88             return major;
89
90         major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
91                                            &ctx->checksumType);
92         if (GSS_ERROR(major))
93             return major;
94     } else {
95         /*
96          * draft-howlett-eap-gss says that integrity/confidentialty should
97          * always be advertised as available, but if we have no keying
98          * material it seems confusing to the caller to advertise this.
99          */
100         ctx->gssFlags &= ~(GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
101         ctx->encryptionType = ENCTYPE_NULL;
102     }
103
104     major = sequenceInit(minor,
105                          &ctx->seqState, ctx->recvSeq,
106                          ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
107                          ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
108                          TRUE);
109     if (GSS_ERROR(major))
110         return major;
111
112     return GSS_S_COMPLETE;
113 }
114
115 static OM_uint32
116 eapGssSmAcceptIdentity(OM_uint32 *minor,
117                        gss_ctx_id_t ctx,
118                        gss_cred_id_t cred,
119                        gss_buffer_t inputToken,
120                        gss_channel_bindings_t chanBindings,
121                        gss_buffer_t outputToken)
122 {
123     OM_uint32 major;
124     union {
125         struct eap_hdr pdu;
126         unsigned char data[5];
127     } pkt;
128     gss_buffer_desc pktBuffer;
129
130     if (inputToken != GSS_C_NO_BUFFER && inputToken->length != 0)
131         return GSS_S_DEFECTIVE_TOKEN;
132
133     assert(ctx->acceptorCtx.radHandle == NULL);
134
135     major = gssEapRadiusAllocHandle(minor, cred, &ctx->acceptorCtx.radHandle);
136     if (GSS_ERROR(major))
137         return major;
138
139     assert(ctx->acceptorName == GSS_C_NO_NAME);
140
141     if (cred != GSS_C_NO_CREDENTIAL && cred->name != GSS_C_NO_NAME) {
142         major = gssEapDuplicateName(minor, cred->name, &ctx->acceptorName);
143         if (GSS_ERROR(major))
144             return major;
145     }
146
147     pkt.pdu.code = EAP_CODE_REQUEST;
148     pkt.pdu.identifier = 0;
149     pkt.pdu.length = htons(sizeof(pkt.data));
150     pkt.data[4] = EAP_TYPE_IDENTITY;
151
152     pktBuffer.length = sizeof(pkt.data);
153     pktBuffer.value = pkt.data;
154
155     major = duplicateBuffer(minor, &pktBuffer, outputToken);
156     if (GSS_ERROR(major))
157         return major;
158
159     ctx->state = EAP_STATE_AUTHENTICATE;
160
161     return GSS_S_CONTINUE_NEEDED;
162 }
163
164 static OM_uint32
165 setAcceptorIdentity(OM_uint32 *minor,
166                     gss_ctx_id_t ctx,
167                     VALUE_PAIR **avps)
168 {
169     OM_uint32 major;
170     gss_buffer_desc nameBuf;
171     krb5_context krbContext = NULL;
172     krb5_principal krbPrinc;
173
174     /* Awaits further specification */
175     if (ctx->acceptorName == GSS_C_NO_NAME)
176         return GSS_S_COMPLETE;
177
178     GSSEAP_KRB_INIT(&krbContext);
179
180     krbPrinc = ctx->acceptorName->krbPrincipal;
181     assert(krbPrinc != NULL);
182
183     if (krb5_princ_size(krbContext, krbPrinc) < 2)
184         return GSS_S_BAD_NAME;
185
186     /* Acceptor-Service-Name */
187     krbDataToGssBuffer(krb5_princ_component(krbContext, krbPrinc, 0), &nameBuf);
188
189     major = addAvpFromBuffer(minor, ctx->acceptorCtx.radHandle, avps,
190                              VENDOR_ATTR_GSS_ACCEPTOR_SERVICE_NAME,
191                              VENDOR_ID_UKERNA,
192                              &nameBuf);
193     if (GSS_ERROR(major))
194         return major;
195
196     /* Acceptor-Host-Name */
197     krbDataToGssBuffer(krb5_princ_component(krbContext, krbPrinc, 1), &nameBuf);
198
199     major = addAvpFromBuffer(minor, ctx->acceptorCtx.radHandle, avps,
200                              VENDOR_ATTR_GSS_ACCEPTOR_HOST_NAME,
201                              VENDOR_ID_UKERNA,
202                              &nameBuf);
203     if (GSS_ERROR(major))
204         return major;
205
206     if (krb5_princ_size(krbContext, krbPrinc) > 2) {
207         /* Acceptor-Service-Specific */
208         krb5_principal_data ssiPrinc = *krbPrinc;
209         char *ssi;
210
211         krb5_princ_size(krbContext, &ssiPrinc) -= 2;
212         krb5_princ_name(krbContext, &ssiPrinc) += 2;
213
214         *minor = krb5_unparse_name_flags(krbContext, &ssiPrinc,
215                                          KRB5_PRINCIPAL_UNPARSE_NO_REALM, &ssi);
216         if (*minor != 0)
217             return GSS_S_FAILURE;
218
219         nameBuf.value = ssi;
220         nameBuf.length = strlen(ssi);
221
222         major = addAvpFromBuffer(minor, ctx->acceptorCtx.radHandle, avps,
223                                  VENDOR_ATTR_GSS_ACCEPTOR_SERVICE_SPECIFIC,
224                                  VENDOR_ID_UKERNA,
225                                  &nameBuf);
226
227         if (GSS_ERROR(major)) {
228             krb5_free_unparsed_name(krbContext, ssi);
229             return major;
230         }
231         krb5_free_unparsed_name(krbContext, ssi);
232     }
233
234     krbDataToGssBuffer(krb5_princ_realm(krbContext, krbPrinc), &nameBuf);
235     if (nameBuf.length != 0) {
236         /* Acceptor-Realm-Name */
237         major = addAvpFromBuffer(minor, ctx->acceptorCtx.radHandle, avps,
238                                  VENDOR_ATTR_GSS_ACCEPTOR_REALM_NAME,
239                                  VENDOR_ID_UKERNA,
240                                  &nameBuf);
241         if (GSS_ERROR(major))
242             return major;
243     }
244
245     return GSS_S_COMPLETE;
246 }
247
248 static OM_uint32
249 eapGssSmAcceptAuthenticate(OM_uint32 *minor,
250                            gss_ctx_id_t ctx,
251                            gss_cred_id_t cred,
252                            gss_buffer_t inputToken,
253                            gss_channel_bindings_t chanBindings,
254                            gss_buffer_t outputToken)
255 {
256     OM_uint32 major, tmpMinor;
257     int code;
258     VALUE_PAIR *send = NULL;
259     VALUE_PAIR *received = NULL;
260     rc_handle *rh = ctx->acceptorCtx.radHandle;
261     char msgBuffer[4096];
262     struct eap_hdr *pdu;
263     unsigned char *pos;
264     gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
265
266     pdu = (struct eap_hdr *)inputToken->value;
267     pos = (unsigned char *)(pdu + 1);
268
269     if (inputToken->length > sizeof(*pdu) &&
270         pdu->code == EAP_CODE_RESPONSE &&
271         pos[0] == EAP_TYPE_IDENTITY) {
272         /*
273          * XXX TODO do we really need to set User-Name? FreeRADIUS does
274          * not appear to require it.
275          */
276         major = addAvpFromBuffer(minor, rh, &send, PW_USER_NAME, 0, &nameBuf);
277         if (GSS_ERROR(major))
278             goto cleanup;
279
280         major = setAcceptorIdentity(minor, ctx, &send);
281         if (GSS_ERROR(major))
282             goto cleanup;
283     }
284
285     major = addAvpFromBuffer(minor, rh, &send, PW_EAP_MESSAGE, 0, inputToken);
286     if (GSS_ERROR(major))
287         goto cleanup;
288
289     if (ctx->acceptorCtx.lastStatus == CHALLENGE_RC) {
290         major = addAvpFromBuffer(minor, rh, &send, PW_STATE, 0,
291                                  &ctx->acceptorCtx.state);
292         if (GSS_ERROR(major))
293             goto cleanup;
294
295         gss_release_buffer(&tmpMinor, &ctx->acceptorCtx.state);
296     }
297
298     code = rc_auth(rh, 0, send, &received, msgBuffer);
299     switch (code) {
300     case OK_RC:
301     case CHALLENGE_RC:
302         major = GSS_S_CONTINUE_NEEDED;
303         break;
304     case TIMEOUT_RC:
305         major = GSS_S_UNAVAILABLE;
306         break;
307     case REJECT_RC:
308         major = GSS_S_DEFECTIVE_CREDENTIAL;
309         break;
310     default:
311         major = GSS_S_FAILURE;
312         goto cleanup;
313     }
314
315     if (GSS_ERROR(major))
316         goto cleanup;
317
318     ctx->acceptorCtx.lastStatus = code;
319
320     major = getBufferFromAvps(minor, received, PW_EAP_MESSAGE, 0,
321                               outputToken, TRUE);
322     if ((major == GSS_S_UNAVAILABLE && code != OK_RC) ||
323         GSS_ERROR(major))
324         goto cleanup;
325
326     if (code == CHALLENGE_RC) {
327         major = getBufferFromAvps(minor, received, PW_STATE, 0,
328                                   &ctx->acceptorCtx.state, TRUE);
329         if (major != GSS_S_UNAVAILABLE && GSS_ERROR(major))
330             goto cleanup;
331     } else {
332         ctx->acceptorCtx.avps = received;
333         received = NULL;
334
335         major = acceptReadyEap(minor, ctx, cred);
336         if (GSS_ERROR(major))
337             goto cleanup;
338
339         ctx->state = EAP_STATE_EXTENSIONS_REQ;
340     }
341
342     major = GSS_S_CONTINUE_NEEDED;
343
344 cleanup:
345     if (received != NULL)
346         rc_avpair_free(received);
347
348     return major;
349 }
350
351 static OM_uint32
352 acceptGssChannelBindings(OM_uint32 *minor,
353                          gss_ctx_id_t ctx,
354                          gss_cred_id_t cred,
355                          gss_buffer_t inputToken,
356                          gss_channel_bindings_t chanBindings)
357 {
358     OM_uint32 major, tmpMinor;
359     gss_iov_buffer_desc iov[2];
360
361     iov[0].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
362     iov[0].buffer.length = 0;
363     iov[0].buffer.value = NULL;
364
365     iov[1].type = GSS_IOV_BUFFER_TYPE_STREAM;
366     iov[1].buffer = *inputToken;
367
368     major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
369                                     iov, 2, TOK_TYPE_WRAP);
370     if (GSS_ERROR(major))
371         return major;
372
373     if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS &&
374         !bufferEqual(&iov[0].buffer, &chanBindings->application_data)) {
375         major = GSS_S_BAD_BINDINGS;
376     } else {
377         major = GSS_S_CONTINUE_NEEDED;
378     }
379
380     gss_release_buffer(&tmpMinor, &iov[0].buffer);
381
382     return major;
383 }
384
385 static OM_uint32
386 eapGssSmAcceptExtensionsReq(OM_uint32 *minor,
387                             gss_ctx_id_t ctx,
388                             gss_cred_id_t cred,
389                             gss_buffer_t inputToken,
390                             gss_channel_bindings_t chanBindings,
391                             gss_buffer_t outputToken)
392 {
393     OM_uint32 major;
394
395     outputToken->length = 0;
396     outputToken->value = NULL;
397
398     major = acceptGssChannelBindings(minor, ctx, cred, inputToken,
399                                      chanBindings);
400     if (GSS_ERROR(major))
401         return major;
402
403     ctx->state = EAP_STATE_EXTENSIONS_RESP;
404
405     return GSS_S_CONTINUE_NEEDED;
406 }
407
408 static OM_uint32
409 eapGssSmAcceptExtensionsResp(OM_uint32 *minor,
410                              gss_ctx_id_t ctx,
411                              gss_cred_id_t cred,
412                              gss_buffer_t inputToken,
413                              gss_channel_bindings_t chanBindings,
414                              gss_buffer_t outputToken)
415 {
416     OM_uint32 major, tmpMinor;
417     gss_buffer_desc credsToken = GSS_C_EMPTY_BUFFER;
418
419 #ifdef GSSEAP_ENABLE_REAUTH
420     major = gssEapMakeReauthCreds(minor, ctx, cred, &credsToken);
421     if (GSS_ERROR(major))
422         return major;
423 #else
424     credsToken.value = "";
425 #endif /* GSSEAP_ENABLE_REAUTH */
426
427     major = duplicateBuffer(minor, &credsToken, outputToken);
428     if (GSS_ERROR(major)) {
429         gss_release_buffer(&tmpMinor, &credsToken);
430         return major;
431     }
432
433 #ifdef GSSEAP_ENABLE_REAUTH
434     gss_release_buffer(&tmpMinor, &credsToken);
435 #endif
436
437     ctx->state = EAP_STATE_ESTABLISHED;
438
439     return GSS_S_COMPLETE;
440 }
441
442 static OM_uint32
443 eapGssSmAcceptEstablished(OM_uint32 *minor,
444                           gss_ctx_id_t ctx,
445                           gss_cred_id_t cred,
446                           gss_buffer_t inputToken,
447                           gss_channel_bindings_t chanBindings,
448                           gss_buffer_t outputToken)
449 {
450     /* Called with already established context */
451     *minor = EINVAL;
452     return GSS_S_BAD_STATUS;
453 }
454
455 static struct gss_eap_acceptor_sm {
456     enum gss_eap_token_type inputTokenType;
457     enum gss_eap_token_type outputTokenType;
458     OM_uint32 (*processToken)(OM_uint32 *,
459                               gss_ctx_id_t,
460                               gss_cred_id_t,
461                               gss_buffer_t,
462                               gss_channel_bindings_t,
463                               gss_buffer_t);
464 } eapGssAcceptorSm[] = {
465     { TOK_TYPE_EAP_RESP,    TOK_TYPE_EAP_REQ,    eapGssSmAcceptIdentity           },
466     { TOK_TYPE_EAP_RESP,    TOK_TYPE_EAP_REQ,    eapGssSmAcceptAuthenticate       },
467     { TOK_TYPE_EXT_REQ,     TOK_TYPE_NONE,       eapGssSmAcceptExtensionsReq      },
468     { TOK_TYPE_NONE,        TOK_TYPE_EXT_RESP,   eapGssSmAcceptExtensionsResp     },
469     { TOK_TYPE_NONE,        TOK_TYPE_NONE,       eapGssSmAcceptEstablished        },
470 #ifdef GSSEAP_ENABLE_REAUTH
471     { TOK_TYPE_GSS_REAUTH,  TOK_TYPE_GSS_REAUTH, eapGssSmAcceptGssReauth          },
472 #endif
473 };
474
475 OM_uint32
476 gss_accept_sec_context(OM_uint32 *minor,
477                        gss_ctx_id_t *context_handle,
478                        gss_cred_id_t cred,
479                        gss_buffer_t input_token,
480                        gss_channel_bindings_t input_chan_bindings,
481                        gss_name_t *src_name,
482                        gss_OID *mech_type,
483                        gss_buffer_t output_token,
484                        OM_uint32 *ret_flags,
485                        OM_uint32 *time_rec,
486                        gss_cred_id_t *delegated_cred_handle)
487 {
488     OM_uint32 major;
489     OM_uint32 tmpMajor, tmpMinor;
490     gss_ctx_id_t ctx = *context_handle;
491     struct gss_eap_acceptor_sm *sm = NULL;
492     gss_buffer_desc innerInputToken = GSS_C_EMPTY_BUFFER;
493     gss_buffer_desc innerOutputToken = GSS_C_EMPTY_BUFFER;
494     enum gss_eap_token_type tokType;
495     int initialContextToken = 0;
496
497     *minor = 0;
498
499     output_token->length = 0;
500     output_token->value = NULL;
501
502     if (cred != GSS_C_NO_CREDENTIAL && !(cred->flags & CRED_FLAG_ACCEPT)) {
503         return GSS_S_NO_CRED;
504     }
505
506     if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) {
507         return GSS_S_DEFECTIVE_TOKEN;
508     }
509
510     if (ctx == GSS_C_NO_CONTEXT) {
511         major = gssEapAllocContext(minor, &ctx);
512         if (GSS_ERROR(major))
513             return major;
514
515         initialContextToken = 1;
516         *context_handle = ctx;
517     }
518
519     GSSEAP_MUTEX_LOCK(&ctx->mutex);
520
521     sm = &eapGssAcceptorSm[ctx->state];
522
523     major = gssEapVerifyToken(minor, ctx, input_token,
524                               &tokType, &innerInputToken);
525     if (GSS_ERROR(major))
526         goto cleanup;
527
528 #ifdef GSSEAP_ENABLE_REAUTH
529     if (tokType == TOK_TYPE_GSS_REAUTH && initialContextToken) {
530         ctx->state = EAP_STATE_KRB_REAUTH_GSS;
531     } else
532 #endif
533     if (tokType != sm->inputTokenType) {
534         major = GSS_S_DEFECTIVE_TOKEN;
535         goto cleanup;
536     }
537
538     /* If credentials were provided, check they're usable with this mech */
539     if (cred != GSS_C_NO_CREDENTIAL &&
540         !gssEapCredAvailable(cred, ctx->mechanismUsed)) {
541         major = GSS_S_BAD_MECH;
542         goto cleanup;
543     }
544
545     do {
546         sm = &eapGssAcceptorSm[ctx->state];
547
548         major = (sm->processToken)(minor,
549                                    ctx,
550                                    cred,
551                                    &innerInputToken,
552                                    input_chan_bindings,
553                                    &innerOutputToken);
554         if (GSS_ERROR(major))
555             goto cleanup;
556     } while (major == GSS_S_CONTINUE_NEEDED && innerOutputToken.length == 0);
557
558     if (mech_type != NULL) {
559         if (!gssEapInternalizeOid(ctx->mechanismUsed, mech_type))
560             duplicateOid(&tmpMinor, ctx->mechanismUsed, mech_type);
561     }
562     if (innerOutputToken.value != NULL) {
563         tmpMajor = gssEapMakeToken(&tmpMinor, ctx, &innerOutputToken,
564                                    sm->outputTokenType, output_token);
565         if (GSS_ERROR(tmpMajor)) {
566             major = tmpMajor;
567             *minor = tmpMinor;
568             goto cleanup;
569         }
570     }
571     if (ret_flags != NULL)
572         *ret_flags = ctx->gssFlags;
573     if (delegated_cred_handle != NULL)
574         *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
575
576     if (major == GSS_S_COMPLETE) {
577         if (src_name != NULL && ctx->initiatorName != GSS_C_NO_NAME) {
578             major = gssEapDuplicateName(&tmpMinor, ctx->initiatorName, src_name);
579             if (GSS_ERROR(major))
580                 goto cleanup;
581         }
582         if (time_rec != NULL)
583             gssEapContextTime(&tmpMinor, ctx, time_rec);
584     }
585
586     assert(ctx->state == EAP_STATE_ESTABLISHED || major == GSS_S_CONTINUE_NEEDED);
587
588 cleanup:
589     GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
590
591     if (GSS_ERROR(major))
592         gssEapReleaseContext(&tmpMinor, context_handle);
593
594     gss_release_buffer(&tmpMinor, &innerOutputToken);
595
596     return major;
597 }
598
599 #ifdef GSSEAP_ENABLE_REAUTH
600 static OM_uint32
601 acceptReadyKrb(OM_uint32 *minor,
602                gss_ctx_id_t ctx,
603                gss_cred_id_t cred,
604                const gss_name_t initiator,
605                const gss_OID mech,
606                OM_uint32 timeRec)
607 {
608     OM_uint32 major;
609
610     major = gssEapGlueToMechName(minor, initiator, &ctx->initiatorName);
611     if (GSS_ERROR(major))
612         return major;
613
614     if (cred != GSS_C_NO_CREDENTIAL && cred->name != GSS_C_NO_NAME) {
615         major = gssEapDuplicateName(minor, cred->name, &ctx->acceptorName);
616         if (GSS_ERROR(major))
617             return major;
618     }
619
620     major = gssEapReauthComplete(minor, ctx, cred, mech, timeRec);
621     if (GSS_ERROR(major))
622         return major;
623
624     ctx->state = EAP_STATE_ESTABLISHED;
625
626     return GSS_S_COMPLETE;
627 }
628
629 static OM_uint32
630 eapGssSmAcceptGssReauth(OM_uint32 *minor,
631                         gss_ctx_id_t ctx,
632                         gss_cred_id_t cred,
633                         gss_buffer_t inputToken,
634                         gss_channel_bindings_t chanBindings,
635                         gss_buffer_t outputToken)
636 {
637     OM_uint32 major, tmpMinor;
638     gss_cred_id_t krbCred = GSS_C_NO_CREDENTIAL;
639     gss_name_t krbInitiator = GSS_C_NO_NAME;
640     gss_OID mech = GSS_C_NO_OID;
641     OM_uint32 gssFlags, timeRec = GSS_C_INDEFINITE;
642
643     ctx->flags |= CTX_FLAG_KRB_REAUTH_GSS;
644
645     if (cred != GSS_C_NO_CREDENTIAL)
646         krbCred = cred->krbCred;
647
648     major = gssAcceptSecContext(minor,
649                                 &ctx->kerberosCtx,
650                                 krbCred,
651                                 inputToken,
652                                 chanBindings,
653                                 &krbInitiator,
654                                 &mech,
655                                 outputToken,
656                                 &gssFlags,
657                                 &timeRec,
658                                 NULL);
659     if (major == GSS_S_COMPLETE) {
660         major = acceptReadyKrb(minor, ctx, cred,
661                                krbInitiator, mech, timeRec);
662     }
663
664     ctx->gssFlags = gssFlags;
665
666     gssReleaseName(&tmpMinor, &krbInitiator);
667
668     return major;
669 }
670 #endif /* GSSEAP_ENABLE_REAUTH */