2 * Copyright (c) 2011, JANET(UK)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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.
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.
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
34 * Establish a security context on the acceptor (server). These functions
35 * wrap around libradsec and (thus) talk to a RADIUS server or proxy.
38 #include "gssapiP_eap.h"
40 #ifdef GSSEAP_ENABLE_REAUTH
42 eapGssSmAcceptGssReauth(OM_uint32 *minor,
45 gss_buffer_t inputToken,
46 gss_channel_bindings_t chanBindings,
47 gss_buffer_t outputToken);
51 * Mark an acceptor context as ready for cryptographic operations
54 acceptReadyEap(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred)
56 OM_uint32 major, tmpMinor;
58 gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
60 /* Cache encryption type derived from selected mechanism OID */
61 major = gssEapOidToEnctype(minor, ctx->mechanismUsed,
62 &ctx->encryptionType);
66 gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
68 major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.vps,
69 PW_USER_NAME, 0, &vp);
70 if (major == GSS_S_COMPLETE) {
71 nameBuf.length = vp->length;
72 nameBuf.value = vp->vp_strvalue;
74 ctx->gssFlags |= GSS_C_ANON_FLAG;
77 major = gssEapImportName(minor, &nameBuf,
78 (ctx->gssFlags & GSS_C_ANON_FLAG) ?
79 GSS_C_NT_ANONYMOUS : GSS_C_NT_USER_NAME,
84 major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.vps,
85 PW_MS_MPPE_SEND_KEY, VENDORPEC_MS, &vp);
86 if (GSS_ERROR(major)) {
87 *minor = GSSEAP_KEY_UNAVAILABLE;
88 return GSS_S_UNAVAILABLE;
91 major = gssEapDeriveRfc3961Key(minor,
99 major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
101 if (GSS_ERROR(major))
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),
109 if (GSS_ERROR(major))
112 major = gssEapCreateAttrContext(minor, cred, ctx,
113 &ctx->initiatorName->attrCtx,
115 if (GSS_ERROR(major))
119 return GSS_S_COMPLETE;
123 * Emit a identity EAP request to force the initiator (peer) to identify
127 eapGssSmAcceptIdentity(OM_uint32 *minor,
130 gss_buffer_t inputToken,
131 gss_channel_bindings_t chanBindings,
132 gss_buffer_t outputToken)
135 struct wpabuf *reqData;
136 gss_buffer_desc pktBuffer;
138 if (inputToken != GSS_C_NO_BUFFER && inputToken->length != 0) {
139 *minor = GSSEAP_WRONG_SIZE;
140 return GSS_S_DEFECTIVE_TOKEN;
143 assert(ctx->acceptorName == GSS_C_NO_NAME);
145 if (cred->name != GSS_C_NO_NAME) {
146 major = gssEapDuplicateName(minor, cred->name, &ctx->acceptorName);
147 if (GSS_ERROR(major))
151 reqData = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, 0,
152 EAP_CODE_REQUEST, 0);
153 if (reqData == NULL) {
155 return GSS_S_FAILURE;
158 pktBuffer.length = wpabuf_len(reqData);
159 pktBuffer.value = (void *)wpabuf_head(reqData);
161 major = duplicateBuffer(minor, &pktBuffer, outputToken);
162 if (GSS_ERROR(major))
165 ctx->state = GSSEAP_STATE_AUTHENTICATE;
167 wpabuf_free(reqData);
170 return GSS_S_CONTINUE_NEEDED;
174 * Returns TRUE if the input token contains an EAP identity response.
177 isIdentityResponseP(gss_buffer_t inputToken)
179 struct wpabuf respData;
181 wpabuf_set(&respData, inputToken->value, inputToken->length);
183 return (eap_get_type(&respData) == EAP_TYPE_IDENTITY);
187 * Pass the asserted initiator identity to the authentication server.
190 setInitiatorIdentity(OM_uint32 *minor,
191 gss_buffer_t inputToken,
194 struct wpabuf respData;
195 const unsigned char *pos;
197 gss_buffer_desc nameBuf;
199 wpabuf_set(&respData, inputToken->value, inputToken->length);
201 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
204 *minor = GSSEAP_PEER_BAD_MESSAGE;
205 return GSS_S_DEFECTIVE_TOKEN;
208 nameBuf.value = (void *)pos;
209 nameBuf.length = len;
211 return gssEapRadiusAddAvp(minor, vps, PW_USER_NAME, 0, &nameBuf);
215 * Pass the asserted acceptor identity to the authentication server.
218 setAcceptorIdentity(OM_uint32 *minor,
223 gss_buffer_desc nameBuf;
224 krb5_context krbContext = NULL;
225 krb5_principal krbPrinc;
226 struct rs_context *rc = ctx->acceptorCtx.radContext;
230 if (ctx->acceptorName == GSS_C_NO_NAME) {
232 return GSS_S_COMPLETE;
235 if ((ctx->acceptorName->flags & NAME_FLAG_SERVICE) == 0) {
236 *minor = GSSEAP_BAD_SERVICE_NAME;
237 return GSS_S_BAD_NAME;
240 GSSEAP_KRB_INIT(&krbContext);
242 krbPrinc = ctx->acceptorName->krbPrincipal;
243 assert(krbPrinc != NULL);
244 assert(KRB_PRINC_LENGTH(krbPrinc) >= 2);
246 /* Acceptor-Service-Name */
247 krbPrincComponentToGssBuffer(krbPrinc, 0, &nameBuf);
249 major = gssEapRadiusAddAvp(minor, vps,
250 PW_GSS_ACCEPTOR_SERVICE_NAME,
253 if (GSS_ERROR(major))
256 /* Acceptor-Host-Name */
257 krbPrincComponentToGssBuffer(krbPrinc, 1, &nameBuf);
259 major = gssEapRadiusAddAvp(minor, vps,
260 PW_GSS_ACCEPTOR_HOST_NAME,
263 if (GSS_ERROR(major))
266 if (KRB_PRINC_LENGTH(krbPrinc) > 2) {
267 /* Acceptor-Service-Specific */
268 krb5_principal_data ssiPrinc = *krbPrinc;
271 KRB_PRINC_LENGTH(&ssiPrinc) -= 2;
272 KRB_PRINC_NAME(&ssiPrinc) += 2;
274 *minor = krb5_unparse_name_flags(krbContext, &ssiPrinc,
275 KRB5_PRINCIPAL_UNPARSE_NO_REALM, &ssi);
277 return GSS_S_FAILURE;
280 nameBuf.length = strlen(ssi);
282 major = gssEapRadiusAddAvp(minor, vps,
283 PW_GSS_ACCEPTOR_SERVICE_SPECIFIC,
287 if (GSS_ERROR(major)) {
288 krb5_free_unparsed_name(krbContext, ssi);
291 krb5_free_unparsed_name(krbContext, ssi);
294 krbPrincRealmToGssBuffer(krbPrinc, &nameBuf);
295 if (nameBuf.length != 0) {
296 /* Acceptor-Realm-Name */
297 major = gssEapRadiusAddAvp(minor, vps,
298 PW_GSS_ACCEPTOR_REALM_NAME,
301 if (GSS_ERROR(major))
306 return GSS_S_COMPLETE;
310 * Allocate a RadSec handle
313 createRadiusHandle(OM_uint32 *minor,
317 struct gss_eap_acceptor_ctx *actx = &ctx->acceptorCtx;
318 const char *configFile = RS_CONFIG_FILE;
319 const char *configStanza = "gss-eap";
320 struct rs_alloc_scheme ralloc;
321 struct rs_error *err;
323 assert(actx->radContext == NULL);
324 assert(actx->radConn == NULL);
326 if (rs_context_create(&actx->radContext, RS_DICT_FILE) != 0) {
327 *minor = GSSEAP_RADSEC_CONTEXT_FAILURE;
328 return GSS_S_FAILURE;
331 if (cred->radiusConfigFile != NULL)
332 configFile = cred->radiusConfigFile;
333 if (cred->radiusConfigStanza != NULL)
334 configStanza = cred->radiusConfigStanza;
336 ralloc.calloc = GSSEAP_CALLOC;
337 ralloc.malloc = GSSEAP_MALLOC;
338 ralloc.free = GSSEAP_FREE;
339 ralloc.realloc = GSSEAP_REALLOC;
341 rs_context_set_alloc_scheme(actx->radContext, &ralloc);
343 if (rs_context_read_config(actx->radContext, configFile) != 0) {
344 err = rs_err_ctx_pop(actx->radContext);
348 if (rs_conn_create(actx->radContext, &actx->radConn, configStanza) != 0) {
349 err = rs_err_conn_pop(actx->radConn);
353 if (actx->radServer != NULL) {
354 if (rs_conn_select_peer(actx->radConn, actx->radServer) != 0) {
355 err = rs_err_conn_pop(actx->radConn);
361 return GSS_S_COMPLETE;
364 return gssEapRadiusMapError(minor, err);
368 * Process a EAP response from the initiator.
371 eapGssSmAcceptAuthenticate(OM_uint32 *minor,
374 gss_buffer_t inputToken,
375 gss_channel_bindings_t chanBindings,
376 gss_buffer_t outputToken)
378 OM_uint32 major, tmpMinor;
379 struct rs_connection *rconn;
380 struct rs_request *request = NULL;
381 struct rs_packet *req = NULL, *resp = NULL;
382 struct radius_packet *frreq, *frresp;
383 int isIdentityResponse = isIdentityResponseP(inputToken);
385 if (ctx->acceptorCtx.radContext == NULL) {
386 /* May be NULL from an imported partial context */
387 major = createRadiusHandle(minor, cred, ctx);
388 if (GSS_ERROR(major))
392 rconn = ctx->acceptorCtx.radConn;
394 if (rs_packet_create_authn_request(rconn, &req, NULL, NULL) != 0) {
395 major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn));
398 frreq = rs_packet_frpkt(req);
400 if (isIdentityResponse) {
401 major = setInitiatorIdentity(minor, inputToken, &frreq->vps);
402 if (GSS_ERROR(major))
405 major = setAcceptorIdentity(minor, ctx, &frreq->vps);
406 if (GSS_ERROR(major))
410 major = gssEapRadiusAddAvp(minor, &frreq->vps,
411 PW_EAP_MESSAGE, 0, inputToken);
412 if (GSS_ERROR(major))
415 if (ctx->acceptorCtx.state.length != 0) {
416 major = gssEapRadiusAddAvp(minor, &frreq->vps, PW_STATE, 0,
417 &ctx->acceptorCtx.state);
418 if (GSS_ERROR(major))
421 gss_release_buffer(&tmpMinor, &ctx->acceptorCtx.state);
424 if (rs_request_create(rconn, &request) != 0) {
425 major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn));
429 rs_request_add_reqpkt(request, req);
432 if (rs_request_send(request, &resp) != 0) {
433 major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn));
437 assert(resp != NULL);
439 frresp = rs_packet_frpkt(resp);
440 switch (frresp->code) {
441 case PW_AUTHENTICATION_ACK:
442 case PW_ACCESS_CHALLENGE:
443 major = GSS_S_CONTINUE_NEEDED;
445 case PW_AUTHENTICATION_REJECT:
446 *minor = GSSEAP_RADIUS_AUTH_FAILURE;
447 major = GSS_S_DEFECTIVE_CREDENTIAL;
451 *minor = GSSEAP_UNKNOWN_RADIUS_CODE;
452 major = GSS_S_FAILURE;
457 major = gssEapRadiusGetAvp(minor, frresp->vps, PW_EAP_MESSAGE, 0,
459 if (major == GSS_S_UNAVAILABLE && frresp->code == PW_ACCESS_CHALLENGE) {
460 *minor = GSSEAP_MISSING_EAP_REQUEST;
461 major = GSS_S_DEFECTIVE_TOKEN;
463 } else if (GSS_ERROR(major))
466 if (frresp->code == PW_ACCESS_CHALLENGE) {
467 major = gssEapRadiusGetAvp(minor, frresp->vps, PW_STATE, 0,
468 &ctx->acceptorCtx.state, TRUE);
469 if (GSS_ERROR(major) && *minor != GSSEAP_NO_SUCH_ATTR)
472 ctx->acceptorCtx.vps = frresp->vps;
475 rs_conn_destroy(ctx->acceptorCtx.radConn);
476 ctx->acceptorCtx.radConn = NULL;
478 major = acceptReadyEap(minor, ctx, cred);
479 if (GSS_ERROR(major))
482 ctx->state = GSSEAP_STATE_EXTENSIONS_REQ;
486 major = GSS_S_CONTINUE_NEEDED;
490 rs_request_destroy(request);
492 rs_packet_destroy(req);
498 eapGssSmAcceptExtensionsReq(OM_uint32 *minor,
501 gss_buffer_t inputToken,
502 gss_channel_bindings_t chanBindings,
503 gss_buffer_t outputToken)
507 major = gssEapVerifyExtensions(minor, cred, ctx, chanBindings, inputToken);
508 if (GSS_ERROR(major))
511 outputToken->length = 0;
512 outputToken->value = NULL;
514 ctx->state = GSSEAP_STATE_EXTENSIONS_RESP;
517 return GSS_S_CONTINUE_NEEDED;
521 eapGssSmAcceptExtensionsResp(OM_uint32 *minor,
524 gss_buffer_t inputToken,
525 gss_channel_bindings_t chanBindings,
526 gss_buffer_t outputToken)
530 major = gssEapMakeExtensions(minor, cred, ctx, chanBindings, outputToken);
531 if (GSS_ERROR(major))
534 ctx->state = GSSEAP_STATE_ESTABLISHED;
537 return GSS_S_COMPLETE;
541 eapGssSmAcceptEstablished(OM_uint32 *minor,
544 gss_buffer_t inputToken,
545 gss_channel_bindings_t chanBindings,
546 gss_buffer_t outputToken)
548 /* Called with already established context */
549 *minor = GSSEAP_CONTEXT_ESTABLISHED;
550 return GSS_S_BAD_STATUS;
554 makeErrorToken(OM_uint32 *minor,
555 OM_uint32 majorStatus,
556 OM_uint32 minorStatus,
557 gss_buffer_t outputToken)
559 unsigned char errorData[8];
560 gss_buffer_desc errorBuffer;
562 assert(GSS_ERROR(majorStatus));
565 * Only return error codes that the initiator could have caused,
566 * to avoid information leakage.
568 if (IS_RADIUS_ERROR(minorStatus)) {
569 /* Squash RADIUS error codes */
570 minorStatus = GSSEAP_RADIUS_PROT_FAILURE;
571 } else if (!IS_WIRE_ERROR(minorStatus)) {
572 /* Don't return non-wire error codes */
573 return GSS_S_COMPLETE;
576 minorStatus -= ERROR_TABLE_BASE_eapg;
578 store_uint32_be(majorStatus, &errorData[0]);
579 store_uint32_be(minorStatus, &errorData[4]);
581 errorBuffer.length = sizeof(errorData);
582 errorBuffer.value = errorData;
584 return duplicateBuffer(minor, &errorBuffer, outputToken);
587 static struct gss_eap_acceptor_sm {
588 enum gss_eap_token_type inputTokenType;
589 enum gss_eap_token_type outputTokenType;
590 OM_uint32 (*processToken)(OM_uint32 *,
594 gss_channel_bindings_t,
596 } eapGssAcceptorSm[] = {
597 { TOK_TYPE_EAP_RESP, TOK_TYPE_EAP_REQ, eapGssSmAcceptIdentity },
598 { TOK_TYPE_EAP_RESP, TOK_TYPE_EAP_REQ, eapGssSmAcceptAuthenticate },
599 { TOK_TYPE_EXT_REQ, TOK_TYPE_NONE, eapGssSmAcceptExtensionsReq },
600 { TOK_TYPE_NONE, TOK_TYPE_EXT_RESP, eapGssSmAcceptExtensionsResp },
601 { TOK_TYPE_NONE, TOK_TYPE_NONE, eapGssSmAcceptEstablished },
602 { TOK_TYPE_NONE, TOK_TYPE_CONTEXT_ERR, NULL },
603 #ifdef GSSEAP_ENABLE_REAUTH
604 { TOK_TYPE_GSS_REAUTH, TOK_TYPE_GSS_REAUTH, eapGssSmAcceptGssReauth },
609 gss_accept_sec_context(OM_uint32 *minor,
610 gss_ctx_id_t *context_handle,
612 gss_buffer_t input_token,
613 gss_channel_bindings_t input_chan_bindings,
614 gss_name_t *src_name,
616 gss_buffer_t output_token,
617 OM_uint32 *ret_flags,
619 gss_cred_id_t *delegated_cred_handle)
622 OM_uint32 tmpMajor, tmpMinor;
623 gss_ctx_id_t ctx = *context_handle;
624 struct gss_eap_acceptor_sm *sm = NULL;
625 gss_buffer_desc innerInputToken = GSS_C_EMPTY_BUFFER;
626 gss_buffer_desc innerOutputToken = GSS_C_EMPTY_BUFFER;
627 enum gss_eap_token_type tokType;
628 int initialContextToken = 0;
632 output_token->length = 0;
633 output_token->value = NULL;
635 if (src_name != NULL)
636 *src_name = GSS_C_NO_NAME;
638 if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) {
639 *minor = GSSEAP_TOK_TRUNC;
640 return GSS_S_DEFECTIVE_TOKEN;
643 if (ctx == GSS_C_NO_CONTEXT) {
644 major = gssEapAllocContext(minor, &ctx);
645 if (GSS_ERROR(major))
648 initialContextToken = 1;
649 *context_handle = ctx;
652 GSSEAP_MUTEX_LOCK(&ctx->mutex);
654 if (cred == GSS_C_NO_CREDENTIAL) {
655 if (ctx->defaultCred == GSS_C_NO_CREDENTIAL) {
656 major = gssEapAcquireCred(minor,
665 if (GSS_ERROR(major))
669 cred = ctx->defaultCred;
672 GSSEAP_MUTEX_LOCK(&cred->mutex);
674 sm = &eapGssAcceptorSm[ctx->state];
676 major = gssEapVerifyToken(minor, ctx, input_token,
677 &tokType, &innerInputToken);
678 if (GSS_ERROR(major))
681 if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) {
682 *minor = GSSEAP_CRED_MECH_MISMATCH;
683 major = GSS_S_BAD_MECH;
687 #ifdef GSSEAP_ENABLE_REAUTH
689 * If we're built with fast reauthentication support, it's valid
690 * for an initiator to send a GSS reauthentication token as its
691 * initial context token, causing us to short-circuit the state
692 * machine and process Kerberos GSS messages instead.
694 if (tokType == TOK_TYPE_GSS_REAUTH && initialContextToken) {
695 ctx->state = GSSEAP_STATE_KRB_REAUTH;
698 if (tokType != sm->inputTokenType) {
699 *minor = GSSEAP_WRONG_TOK_ID;
700 major = GSS_S_DEFECTIVE_TOKEN;
705 sm = &eapGssAcceptorSm[ctx->state];
707 major = (sm->processToken)(minor,
713 if (GSS_ERROR(major)) {
714 /* Possibly generate an error token */
715 tmpMajor = makeErrorToken(&tmpMinor, major, *minor, &innerOutputToken);
716 if (GSS_ERROR(tmpMajor)) {
721 sm = &eapGssAcceptorSm[GSSEAP_STATE_ERROR];
724 } while (major == GSS_S_CONTINUE_NEEDED && innerOutputToken.length == 0);
726 if (mech_type != NULL) {
727 if (!gssEapInternalizeOid(ctx->mechanismUsed, mech_type))
728 duplicateOid(&tmpMinor, ctx->mechanismUsed, mech_type);
730 if (ret_flags != NULL)
731 *ret_flags = ctx->gssFlags;
732 if (delegated_cred_handle != NULL)
733 *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
735 if (major == GSS_S_COMPLETE) {
736 if (src_name != NULL && ctx->initiatorName != GSS_C_NO_NAME) {
737 major = gssEapDuplicateName(&tmpMinor, ctx->initiatorName, src_name);
738 if (GSS_ERROR(major))
741 if (time_rec != NULL) {
742 major = gssEapContextTime(&tmpMinor, ctx, time_rec);
743 if (GSS_ERROR(major))
748 assert(ctx->state == GSSEAP_STATE_ESTABLISHED || major == GSS_S_CONTINUE_NEEDED);
751 if (innerOutputToken.value != NULL) {
752 tmpMajor = gssEapMakeToken(&tmpMinor, ctx, &innerOutputToken,
753 sm->outputTokenType, output_token);
754 if (GSS_ERROR(tmpMajor)) {
762 if (cred != GSS_C_NO_CREDENTIAL)
763 GSSEAP_MUTEX_UNLOCK(&cred->mutex);
764 GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
766 if (GSS_ERROR(major))
767 gssEapReleaseContext(&tmpMinor, context_handle);
769 gss_release_buffer(&tmpMinor, &innerOutputToken);
774 #ifdef GSSEAP_ENABLE_REAUTH
776 acceptReadyKrb(OM_uint32 *minor,
779 const gss_name_t initiator,
785 major = gssEapGlueToMechName(minor, ctx, initiator, &ctx->initiatorName);
786 if (GSS_ERROR(major))
789 if (cred->name != GSS_C_NO_NAME) {
790 major = gssEapDuplicateName(minor, cred->name, &ctx->acceptorName);
791 if (GSS_ERROR(major))
795 major = gssEapReauthComplete(minor, ctx, cred, mech, timeRec);
796 if (GSS_ERROR(major))
799 ctx->state = GSSEAP_STATE_ESTABLISHED;
802 return GSS_S_COMPLETE;
806 eapGssSmAcceptGssReauth(OM_uint32 *minor,
809 gss_buffer_t inputToken,
810 gss_channel_bindings_t chanBindings,
811 gss_buffer_t outputToken)
813 OM_uint32 major, tmpMinor;
814 gss_name_t krbInitiator = GSS_C_NO_NAME;
815 gss_OID mech = GSS_C_NO_OID;
816 OM_uint32 gssFlags, timeRec = GSS_C_INDEFINITE;
818 ctx->flags |= CTX_FLAG_KRB_REAUTH;
820 major = gssAcceptSecContext(minor,
831 if (major == GSS_S_COMPLETE) {
832 major = acceptReadyKrb(minor, ctx, cred,
833 krbInitiator, mech, timeRec);
836 ctx->gssFlags = gssFlags;
838 gssReleaseName(&tmpMinor, &krbInitiator);
842 #endif /* GSSEAP_ENABLE_REAUTH */