cleanup, filter secret attributes before copying
[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     major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.vps,
64                                   PW_USER_NAME, 0, &vp);
65     if (major == GSS_S_COMPLETE) {
66         nameBuf.length = vp->length;
67         nameBuf.value = vp->vp_strvalue;
68     } else {
69         ctx->gssFlags |= GSS_C_ANON_FLAG;
70     }
71
72     major = gssEapImportName(minor, &nameBuf, GSS_C_NT_USER_NAME,
73                              &ctx->initiatorName);
74     if (GSS_ERROR(major))
75         return major;
76
77     major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.vps,
78                                   PW_MS_MPPE_SEND_KEY, VENDORPEC_MS, &vp);
79     if (GSS_ERROR(major))
80         return major;
81
82     major = gssEapDeriveRfc3961Key(minor,
83                                    vp->vp_octets,
84                                    vp->length,
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
95     major = sequenceInit(minor,
96                          &ctx->seqState, ctx->recvSeq,
97                          ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
98                          ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
99                          TRUE);
100     if (GSS_ERROR(major))
101         return major;
102
103     ctx->initiatorName->attrCtx = gssEapCreateAttrContext(cred, ctx);
104
105     return GSS_S_COMPLETE;
106 }
107
108 static OM_uint32
109 eapGssSmAcceptIdentity(OM_uint32 *minor,
110                        gss_ctx_id_t ctx,
111                        gss_cred_id_t cred,
112                        gss_buffer_t inputToken,
113                        gss_channel_bindings_t chanBindings,
114                        gss_buffer_t outputToken)
115 {
116     OM_uint32 major;
117     union {
118         struct eap_hdr pdu;
119         unsigned char data[5];
120     } pkt;
121     gss_buffer_desc pktBuffer;
122
123     if (inputToken != GSS_C_NO_BUFFER && inputToken->length != 0)
124         return GSS_S_DEFECTIVE_TOKEN;
125
126     assert(ctx->acceptorName == GSS_C_NO_NAME);
127
128     if (cred != GSS_C_NO_CREDENTIAL && cred->name != GSS_C_NO_NAME) {
129         major = gssEapDuplicateName(minor, cred->name, &ctx->acceptorName);
130         if (GSS_ERROR(major))
131             return major;
132     }
133
134     pkt.pdu.code = EAP_CODE_REQUEST;
135     pkt.pdu.identifier = 0;
136     pkt.pdu.length = htons(sizeof(pkt.data));
137     pkt.data[4] = EAP_TYPE_IDENTITY;
138
139     pktBuffer.length = sizeof(pkt.data);
140     pktBuffer.value = pkt.data;
141
142     major = duplicateBuffer(minor, &pktBuffer, outputToken);
143     if (GSS_ERROR(major))
144         return major;
145
146     ctx->state = EAP_STATE_AUTHENTICATE;
147
148     return GSS_S_CONTINUE_NEEDED;
149 }
150
151 static OM_uint32
152 setAcceptorIdentity(OM_uint32 *minor,
153                     gss_ctx_id_t ctx,
154                     VALUE_PAIR **vps)
155 {
156     OM_uint32 major;
157     gss_buffer_desc nameBuf;
158     krb5_context krbContext = NULL;
159     krb5_principal krbPrinc;
160     struct rs_handle *rh = ctx->acceptorCtx.radHandle;
161
162     assert(rh != NULL);
163
164     /* Awaits further specification */
165     if (ctx->acceptorName == GSS_C_NO_NAME)
166         return GSS_S_COMPLETE;
167
168     GSSEAP_KRB_INIT(&krbContext);
169
170     krbPrinc = ctx->acceptorName->krbPrincipal;
171     assert(krbPrinc != NULL);
172
173     if (krb5_princ_size(krbContext, krbPrinc) < 2)
174         return GSS_S_BAD_NAME;
175
176     /* Acceptor-Service-Name */
177     krbDataToGssBuffer(krb5_princ_component(krbContext, krbPrinc, 0), &nameBuf);
178
179     major = gssEapRadiusAddAvp(minor, rh, vps,
180                                PW_GSS_ACCEPTOR_SERVICE_NAME,
181                                VENDORPEC_UKERNA,
182                                &nameBuf);
183     if (GSS_ERROR(major))
184         return major;
185
186     /* Acceptor-Host-Name */
187     krbDataToGssBuffer(krb5_princ_component(krbContext, krbPrinc, 1), &nameBuf);
188
189     major = gssEapRadiusAddAvp(minor, rh, vps,
190                                PW_GSS_ACCEPTOR_HOST_NAME,
191                                VENDORPEC_UKERNA,
192                                &nameBuf);
193     if (GSS_ERROR(major))
194         return major;
195
196     if (krb5_princ_size(krbContext, krbPrinc) > 2) {
197         /* Acceptor-Service-Specific */
198         krb5_principal_data ssiPrinc = *krbPrinc;
199         char *ssi;
200
201         krb5_princ_size(krbContext, &ssiPrinc) -= 2;
202         krb5_princ_name(krbContext, &ssiPrinc) += 2;
203
204         *minor = krb5_unparse_name_flags(krbContext, &ssiPrinc,
205                                          KRB5_PRINCIPAL_UNPARSE_NO_REALM, &ssi);
206         if (*minor != 0)
207             return GSS_S_FAILURE;
208
209         nameBuf.value = ssi;
210         nameBuf.length = strlen(ssi);
211
212         major = gssEapRadiusAddAvp(minor, rh, vps,
213                                    PW_GSS_ACCEPTOR_SERVICE_SPECIFIC,
214                                    VENDORPEC_UKERNA,
215                                    &nameBuf);
216
217         if (GSS_ERROR(major)) {
218             krb5_free_unparsed_name(krbContext, ssi);
219             return major;
220         }
221         krb5_free_unparsed_name(krbContext, ssi);
222     }
223
224     krbDataToGssBuffer(krb5_princ_realm(krbContext, krbPrinc), &nameBuf);
225     if (nameBuf.length != 0) {
226         /* Acceptor-Realm-Name */
227         major = gssEapRadiusAddAvp(minor, rh, vps,
228                                    PW_GSS_ACCEPTOR_REALM_NAME,
229                                    VENDORPEC_UKERNA,
230                                    &nameBuf);
231         if (GSS_ERROR(major))
232             return major;
233     }
234
235     return GSS_S_COMPLETE;
236 }
237
238 static OM_uint32
239 eapGssSmAcceptAuthenticate(OM_uint32 *minor,
240                            gss_ctx_id_t ctx,
241                            gss_cred_id_t cred,
242                            gss_buffer_t inputToken,
243                            gss_channel_bindings_t chanBindings,
244                            gss_buffer_t outputToken)
245 {
246     OM_uint32 major, tmpMinor;
247     struct rs_handle *rh;
248     struct rs_connection *rconn;
249     struct rs_request *request = NULL;
250     struct rs_packet *req = NULL, *resp = NULL;
251     struct radius_packet *frreq, *frresp;
252     int sendAcceptorIdentity = 0;
253
254     if (ctx->acceptorCtx.radHandle == NULL) {
255         /* May be NULL from an imported partial context */
256         major = gssEapRadiusAllocConn(minor, cred, ctx);
257         if (GSS_ERROR(major))
258             goto cleanup;
259
260         sendAcceptorIdentity = 1;
261     }
262
263     rh = ctx->acceptorCtx.radHandle;
264     rconn = ctx->acceptorCtx.radConn;
265
266     if (rs_packet_create_acc_request(rconn, &req, NULL, NULL) != 0) {
267         major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn));
268         goto cleanup;
269     }
270     frreq = rs_packet_frpkt(req);
271
272     if (sendAcceptorIdentity) {
273         major = setAcceptorIdentity(minor, ctx, &frreq->vps);
274         if (GSS_ERROR(major))
275             goto cleanup;
276     }
277
278     major = gssEapRadiusAddAvp(minor, rh, &frreq->vps,
279                                PW_EAP_MESSAGE, 0, inputToken);
280     if (GSS_ERROR(major))
281         goto cleanup;
282
283     if (ctx->acceptorCtx.state.length != 0) {
284         major = gssEapRadiusAddAvp(minor, rh, &frreq->vps, PW_STATE, 0,
285                                    &ctx->acceptorCtx.state);
286         if (GSS_ERROR(major))
287             goto cleanup;
288
289         gss_release_buffer(&tmpMinor, &ctx->acceptorCtx.state);
290     }
291
292     if (rs_request_create(rconn, &request) != 0 ||
293         rs_request_send(request, req, &resp) != 0) {
294         major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn));
295         goto cleanup;
296     }
297
298     assert(resp != NULL);
299
300     frresp = rs_packet_frpkt(resp);
301     switch (frresp->code) {
302     case PW_AUTHENTICATION_ACK:
303     case PW_ACCESS_CHALLENGE:
304         major = GSS_S_CONTINUE_NEEDED;
305         break;
306     case PW_AUTHENTICATION_REJECT:
307         major = GSS_S_DEFECTIVE_CREDENTIAL;
308         goto cleanup;
309         break;
310     default:
311         major = GSS_S_FAILURE;
312         goto cleanup;
313         break;
314     }
315
316     major = gssEapRadiusGetAvp(minor, frresp->vps, PW_EAP_MESSAGE, 0,
317                                outputToken, TRUE);
318     if ((major == GSS_S_UNAVAILABLE && frresp->code != PW_AUTHENTICATION_ACK) ||
319         GSS_ERROR(major))
320         goto cleanup;
321
322     if (frresp->code == PW_ACCESS_CHALLENGE) {
323         major = gssEapRadiusGetAvp(minor, frresp->vps, PW_STATE, 0,
324                                    &ctx->acceptorCtx.state, TRUE);
325         if (major != GSS_S_UNAVAILABLE && GSS_ERROR(major))
326             goto cleanup;
327     } else {
328         ctx->acceptorCtx.vps = frresp->vps;
329         frresp->vps = NULL;
330
331         rs_conn_destroy(ctx->acceptorCtx.radConn);
332         ctx->acceptorCtx.radConn = NULL;
333
334         major = acceptReadyEap(minor, ctx, cred);
335         if (GSS_ERROR(major))
336             goto cleanup;
337
338         ctx->state = EAP_STATE_EXTENSIONS_REQ;
339     }
340
341     major = GSS_S_CONTINUE_NEEDED;
342
343 cleanup:
344     rs_request_destroy(request);
345
346     return major;
347 }
348
349 static OM_uint32
350 acceptGssChannelBindings(OM_uint32 *minor,
351                          gss_ctx_id_t ctx,
352                          gss_cred_id_t cred,
353                          gss_buffer_t inputToken,
354                          gss_channel_bindings_t chanBindings)
355 {
356     OM_uint32 major, tmpMinor;
357     gss_iov_buffer_desc iov[2];
358
359     iov[0].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
360     iov[0].buffer.length = 0;
361     iov[0].buffer.value = NULL;
362
363     iov[1].type = GSS_IOV_BUFFER_TYPE_STREAM;
364     iov[1].buffer = *inputToken;
365
366     major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
367                                     iov, 2, TOK_TYPE_WRAP);
368     if (GSS_ERROR(major))
369         return major;
370
371     if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS &&
372         !bufferEqual(&iov[0].buffer, &chanBindings->application_data)) {
373         major = GSS_S_BAD_BINDINGS;
374     } else {
375         major = GSS_S_CONTINUE_NEEDED;
376     }
377
378     gss_release_buffer(&tmpMinor, &iov[0].buffer);
379
380     return major;
381 }
382
383 static OM_uint32
384 eapGssSmAcceptExtensionsReq(OM_uint32 *minor,
385                             gss_ctx_id_t ctx,
386                             gss_cred_id_t cred,
387                             gss_buffer_t inputToken,
388                             gss_channel_bindings_t chanBindings,
389                             gss_buffer_t outputToken)
390 {
391     OM_uint32 major;
392
393     outputToken->length = 0;
394     outputToken->value = NULL;
395
396     major = acceptGssChannelBindings(minor, ctx, cred, inputToken,
397                                      chanBindings);
398     if (GSS_ERROR(major))
399         return major;
400
401     ctx->state = EAP_STATE_EXTENSIONS_RESP;
402
403     return GSS_S_CONTINUE_NEEDED;
404 }
405
406 static OM_uint32
407 eapGssSmAcceptExtensionsResp(OM_uint32 *minor,
408                              gss_ctx_id_t ctx,
409                              gss_cred_id_t cred,
410                              gss_buffer_t inputToken,
411                              gss_channel_bindings_t chanBindings,
412                              gss_buffer_t outputToken)
413 {
414     OM_uint32 major, tmpMinor;
415     gss_buffer_desc credsToken = GSS_C_EMPTY_BUFFER;
416
417 #ifdef GSSEAP_ENABLE_REAUTH
418     /*
419      * If we're built with fast reauthentication enabled, then
420      * fabricate a ticket from the initiator to ourselves.
421      * Otherwise return an empty token.
422      */
423     major = gssEapMakeReauthCreds(minor, ctx, cred, &credsToken);
424     if (GSS_ERROR(major))
425         return major;
426 #else
427     credsToken.value = "";
428 #endif /* GSSEAP_ENABLE_REAUTH */
429
430     major = duplicateBuffer(minor, &credsToken, outputToken);
431     if (GSS_ERROR(major)) {
432         gss_release_buffer(&tmpMinor, &credsToken);
433         return major;
434     }
435
436 #ifdef GSSEAP_ENABLE_REAUTH
437     gss_release_buffer(&tmpMinor, &credsToken);
438 #endif
439
440     ctx->state = EAP_STATE_ESTABLISHED;
441
442     return GSS_S_COMPLETE;
443 }
444
445 static OM_uint32
446 eapGssSmAcceptEstablished(OM_uint32 *minor,
447                           gss_ctx_id_t ctx,
448                           gss_cred_id_t cred,
449                           gss_buffer_t inputToken,
450                           gss_channel_bindings_t chanBindings,
451                           gss_buffer_t outputToken)
452 {
453     /* Called with already established context */
454     *minor = EINVAL;
455     return GSS_S_BAD_STATUS;
456 }
457
458 static struct gss_eap_acceptor_sm {
459     enum gss_eap_token_type inputTokenType;
460     enum gss_eap_token_type outputTokenType;
461     OM_uint32 (*processToken)(OM_uint32 *,
462                               gss_ctx_id_t,
463                               gss_cred_id_t,
464                               gss_buffer_t,
465                               gss_channel_bindings_t,
466                               gss_buffer_t);
467 } eapGssAcceptorSm[] = {
468     { TOK_TYPE_EAP_RESP,    TOK_TYPE_EAP_REQ,    eapGssSmAcceptIdentity           },
469     { TOK_TYPE_EAP_RESP,    TOK_TYPE_EAP_REQ,    eapGssSmAcceptAuthenticate       },
470     { TOK_TYPE_EXT_REQ,     TOK_TYPE_NONE,       eapGssSmAcceptExtensionsReq      },
471     { TOK_TYPE_NONE,        TOK_TYPE_EXT_RESP,   eapGssSmAcceptExtensionsResp     },
472     { TOK_TYPE_NONE,        TOK_TYPE_NONE,       eapGssSmAcceptEstablished        },
473 #ifdef GSSEAP_ENABLE_REAUTH
474     { TOK_TYPE_GSS_REAUTH,  TOK_TYPE_GSS_REAUTH, eapGssSmAcceptGssReauth          },
475 #endif
476 };
477
478 OM_uint32
479 gss_accept_sec_context(OM_uint32 *minor,
480                        gss_ctx_id_t *context_handle,
481                        gss_cred_id_t cred,
482                        gss_buffer_t input_token,
483                        gss_channel_bindings_t input_chan_bindings,
484                        gss_name_t *src_name,
485                        gss_OID *mech_type,
486                        gss_buffer_t output_token,
487                        OM_uint32 *ret_flags,
488                        OM_uint32 *time_rec,
489                        gss_cred_id_t *delegated_cred_handle)
490 {
491     OM_uint32 major;
492     OM_uint32 tmpMajor, tmpMinor;
493     gss_ctx_id_t ctx = *context_handle;
494     struct gss_eap_acceptor_sm *sm = NULL;
495     gss_buffer_desc innerInputToken = GSS_C_EMPTY_BUFFER;
496     gss_buffer_desc innerOutputToken = GSS_C_EMPTY_BUFFER;
497     enum gss_eap_token_type tokType;
498     int initialContextToken = 0;
499
500     *minor = 0;
501
502     output_token->length = 0;
503     output_token->value = NULL;
504
505     if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) {
506         return GSS_S_DEFECTIVE_TOKEN;
507     }
508
509     if (ctx == GSS_C_NO_CONTEXT) {
510         major = gssEapAllocContext(minor, &ctx);
511         if (GSS_ERROR(major))
512             return major;
513
514         initialContextToken = 1;
515         *context_handle = ctx;
516     }
517
518     GSSEAP_MUTEX_LOCK(&ctx->mutex);
519
520     /* Validate and lock credentials */
521     if (cred != GSS_C_NO_CREDENTIAL) {
522         GSSEAP_MUTEX_LOCK(&cred->mutex);
523
524         if ((cred->flags & CRED_FLAG_ACCEPT) == 0) {
525             major = GSS_S_NO_CRED;
526             goto cleanup;
527         }
528     }
529
530     sm = &eapGssAcceptorSm[ctx->state];
531
532     major = gssEapVerifyToken(minor, ctx, input_token,
533                               &tokType, &innerInputToken);
534     if (GSS_ERROR(major))
535         goto cleanup;
536
537     if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) {
538         major = GSS_S_BAD_MECH;
539         goto cleanup;
540     }
541
542 #ifdef GSSEAP_ENABLE_REAUTH
543     /*
544      * If we're built with fast reauthentication support, it's valid
545      * for an initiator to send a GSS reauthentication token as its
546      * initial context token, causing us to short-circuit the state
547      * machine and process Kerberos GSS messages instead.
548      */
549     if (tokType == TOK_TYPE_GSS_REAUTH && initialContextToken) {
550         ctx->state = EAP_STATE_KRB_REAUTH_GSS;
551     } else
552 #endif
553     if (tokType != sm->inputTokenType) {
554         major = GSS_S_DEFECTIVE_TOKEN;
555         goto cleanup;
556     }
557
558     do {
559         sm = &eapGssAcceptorSm[ctx->state];
560
561         major = (sm->processToken)(minor,
562                                    ctx,
563                                    cred,
564                                    &innerInputToken,
565                                    input_chan_bindings,
566                                    &innerOutputToken);
567         if (GSS_ERROR(major))
568             goto cleanup;
569     } while (major == GSS_S_CONTINUE_NEEDED && innerOutputToken.length == 0);
570
571     if (mech_type != NULL) {
572         if (!gssEapInternalizeOid(ctx->mechanismUsed, mech_type))
573             duplicateOid(&tmpMinor, ctx->mechanismUsed, mech_type);
574     }
575     if (innerOutputToken.value != NULL) {
576         tmpMajor = gssEapMakeToken(&tmpMinor, ctx, &innerOutputToken,
577                                    sm->outputTokenType, output_token);
578         if (GSS_ERROR(tmpMajor)) {
579             major = tmpMajor;
580             *minor = tmpMinor;
581             goto cleanup;
582         }
583     }
584     if (ret_flags != NULL)
585         *ret_flags = ctx->gssFlags;
586     if (delegated_cred_handle != NULL)
587         *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
588
589     if (major == GSS_S_COMPLETE) {
590         if (src_name != NULL && ctx->initiatorName != GSS_C_NO_NAME) {
591             major = gssEapDuplicateName(&tmpMinor, ctx->initiatorName, src_name);
592             if (GSS_ERROR(major))
593                 goto cleanup;
594         }
595         if (time_rec != NULL)
596             gssEapContextTime(&tmpMinor, ctx, time_rec);
597     }
598
599     assert(ctx->state == EAP_STATE_ESTABLISHED || major == GSS_S_CONTINUE_NEEDED);
600
601 cleanup:
602     if (cred != GSS_C_NO_CREDENTIAL)
603         GSSEAP_MUTEX_UNLOCK(&cred->mutex);
604     GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
605
606     if (GSS_ERROR(major))
607         gssEapReleaseContext(&tmpMinor, context_handle);
608
609     gss_release_buffer(&tmpMinor, &innerOutputToken);
610
611     return major;
612 }
613
614 #ifdef GSSEAP_ENABLE_REAUTH
615 static OM_uint32
616 acceptReadyKrb(OM_uint32 *minor,
617                gss_ctx_id_t ctx,
618                gss_cred_id_t cred,
619                const gss_name_t initiator,
620                const gss_OID mech,
621                OM_uint32 timeRec)
622 {
623     OM_uint32 major;
624
625     major = gssEapGlueToMechName(minor, initiator, &ctx->initiatorName);
626     if (GSS_ERROR(major))
627         return major;
628
629     if (cred != GSS_C_NO_CREDENTIAL && cred->name != GSS_C_NO_NAME) {
630         major = gssEapDuplicateName(minor, cred->name, &ctx->acceptorName);
631         if (GSS_ERROR(major))
632             return major;
633     }
634
635     major = gssEapReauthComplete(minor, ctx, cred, mech, timeRec);
636     if (GSS_ERROR(major))
637         return major;
638
639     ctx->state = EAP_STATE_ESTABLISHED;
640
641     return GSS_S_COMPLETE;
642 }
643
644 static OM_uint32
645 eapGssSmAcceptGssReauth(OM_uint32 *minor,
646                         gss_ctx_id_t ctx,
647                         gss_cred_id_t cred,
648                         gss_buffer_t inputToken,
649                         gss_channel_bindings_t chanBindings,
650                         gss_buffer_t outputToken)
651 {
652     OM_uint32 major, tmpMinor;
653     gss_cred_id_t krbCred = GSS_C_NO_CREDENTIAL;
654     gss_name_t krbInitiator = GSS_C_NO_NAME;
655     gss_OID mech = GSS_C_NO_OID;
656     OM_uint32 gssFlags, timeRec = GSS_C_INDEFINITE;
657
658     ctx->flags |= CTX_FLAG_KRB_REAUTH_GSS;
659
660     if (cred != GSS_C_NO_CREDENTIAL)
661         krbCred = cred->krbCred;
662
663     major = gssAcceptSecContext(minor,
664                                 &ctx->kerberosCtx,
665                                 krbCred,
666                                 inputToken,
667                                 chanBindings,
668                                 &krbInitiator,
669                                 &mech,
670                                 outputToken,
671                                 &gssFlags,
672                                 &timeRec,
673                                 NULL);
674     if (major == GSS_S_COMPLETE) {
675         major = acceptReadyKrb(minor, ctx, cred,
676                                krbInitiator, mech, timeRec);
677     }
678
679     ctx->gssFlags = gssFlags;
680
681     gssReleaseName(&tmpMinor, &krbInitiator);
682
683     return major;
684 }
685 #endif /* GSSEAP_ENABLE_REAUTH */