Path: blob/main/crypto/heimdal/lib/gssapi/spnego/accept_sec_context.c
34907 views
/*1* Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan2* (Royal Institute of Technology, Stockholm, Sweden).3* Portions Copyright (c) 2004 PADL Software Pty Ltd.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8*9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11*12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* 3. Neither the name of the Institute nor the names of its contributors17* may be used to endorse or promote products derived from this software18* without specific prior written permission.19*20* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND21* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE23* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE24* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL25* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS26* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)27* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT28* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY29* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF30* SUCH DAMAGE.31*/3233#include "spnego_locl.h"3435static OM_uint3236send_reject (OM_uint32 *minor_status,37gss_buffer_t output_token)38{39NegotiationToken nt;40size_t size;4142nt.element = choice_NegotiationToken_negTokenResp;4344ALLOC(nt.u.negTokenResp.negResult, 1);45if (nt.u.negTokenResp.negResult == NULL) {46*minor_status = ENOMEM;47return GSS_S_FAILURE;48}49*(nt.u.negTokenResp.negResult) = reject;50nt.u.negTokenResp.supportedMech = NULL;51nt.u.negTokenResp.responseToken = NULL;52nt.u.negTokenResp.mechListMIC = NULL;5354ASN1_MALLOC_ENCODE(NegotiationToken,55output_token->value, output_token->length, &nt,56&size, *minor_status);57free_NegotiationToken(&nt);58if (*minor_status != 0)59return GSS_S_FAILURE;6061return GSS_S_BAD_MECH;62}6364static OM_uint3265acceptor_approved(gss_name_t target_name, gss_OID mech)66{67gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;68gss_OID_set oidset;69OM_uint32 junk, ret;7071if (target_name == GSS_C_NO_NAME)72return GSS_S_COMPLETE;7374gss_create_empty_oid_set(&junk, &oidset);75gss_add_oid_set_member(&junk, mech, &oidset);7677ret = gss_acquire_cred(&junk, target_name, GSS_C_INDEFINITE, oidset,78GSS_C_ACCEPT, &cred, NULL, NULL);79gss_release_oid_set(&junk, &oidset);80if (ret != GSS_S_COMPLETE)81return ret;82gss_release_cred(&junk, &cred);8384return GSS_S_COMPLETE;85}8687static OM_uint3288send_supported_mechs (OM_uint32 *minor_status,89gss_buffer_t output_token)90{91NegotiationTokenWin nt;92size_t buf_len = 0;93gss_buffer_desc data;94OM_uint32 ret;9596memset(&nt, 0, sizeof(nt));9798nt.element = choice_NegotiationTokenWin_negTokenInit;99nt.u.negTokenInit.reqFlags = NULL;100nt.u.negTokenInit.mechToken = NULL;101nt.u.negTokenInit.negHints = NULL;102103ret = _gss_spnego_indicate_mechtypelist(minor_status, GSS_C_NO_NAME,104acceptor_approved, 1, NULL,105&nt.u.negTokenInit.mechTypes, NULL);106if (ret != GSS_S_COMPLETE) {107return ret;108}109110ALLOC(nt.u.negTokenInit.negHints, 1);111if (nt.u.negTokenInit.negHints == NULL) {112*minor_status = ENOMEM;113free_NegotiationTokenWin(&nt);114return GSS_S_FAILURE;115}116117ALLOC(nt.u.negTokenInit.negHints->hintName, 1);118if (nt.u.negTokenInit.negHints->hintName == NULL) {119*minor_status = ENOMEM;120free_NegotiationTokenWin(&nt);121return GSS_S_FAILURE;122}123124*nt.u.negTokenInit.negHints->hintName = strdup("not_defined_in_RFC4178@please_ignore");125nt.u.negTokenInit.negHints->hintAddress = NULL;126127ASN1_MALLOC_ENCODE(NegotiationTokenWin,128data.value, data.length, &nt, &buf_len, ret);129free_NegotiationTokenWin(&nt);130if (ret) {131*minor_status = ret;132return GSS_S_FAILURE;133}134if (data.length != buf_len) {135abort();136UNREACHABLE(return GSS_S_FAILURE);137}138139ret = gss_encapsulate_token(&data, GSS_SPNEGO_MECHANISM, output_token);140141free (data.value);142143if (ret != GSS_S_COMPLETE)144return ret;145146*minor_status = 0;147148return GSS_S_CONTINUE_NEEDED;149}150151static OM_uint32152send_accept (OM_uint32 *minor_status,153gssspnego_ctx context_handle,154gss_buffer_t mech_token,155int initial_response,156gss_buffer_t mech_buf,157gss_buffer_t output_token)158{159NegotiationToken nt;160OM_uint32 ret;161gss_buffer_desc mech_mic_buf;162size_t size;163164memset(&nt, 0, sizeof(nt));165166nt.element = choice_NegotiationToken_negTokenResp;167168ALLOC(nt.u.negTokenResp.negResult, 1);169if (nt.u.negTokenResp.negResult == NULL) {170*minor_status = ENOMEM;171return GSS_S_FAILURE;172}173174if (context_handle->open) {175if (mech_token != GSS_C_NO_BUFFER176&& mech_token->length != 0177&& mech_buf != GSS_C_NO_BUFFER)178*(nt.u.negTokenResp.negResult) = accept_incomplete;179else180*(nt.u.negTokenResp.negResult) = accept_completed;181} else {182if (initial_response && context_handle->require_mic)183*(nt.u.negTokenResp.negResult) = request_mic;184else185*(nt.u.negTokenResp.negResult) = accept_incomplete;186}187188if (initial_response) {189ALLOC(nt.u.negTokenResp.supportedMech, 1);190if (nt.u.negTokenResp.supportedMech == NULL) {191free_NegotiationToken(&nt);192*minor_status = ENOMEM;193return GSS_S_FAILURE;194}195196ret = der_get_oid(context_handle->preferred_mech_type->elements,197context_handle->preferred_mech_type->length,198nt.u.negTokenResp.supportedMech,199NULL);200if (ret) {201free_NegotiationToken(&nt);202*minor_status = ENOMEM;203return GSS_S_FAILURE;204}205} else {206nt.u.negTokenResp.supportedMech = NULL;207}208209if (mech_token != GSS_C_NO_BUFFER && mech_token->length != 0) {210ALLOC(nt.u.negTokenResp.responseToken, 1);211if (nt.u.negTokenResp.responseToken == NULL) {212free_NegotiationToken(&nt);213*minor_status = ENOMEM;214return GSS_S_FAILURE;215}216nt.u.negTokenResp.responseToken->length = mech_token->length;217nt.u.negTokenResp.responseToken->data = mech_token->value;218mech_token->length = 0;219mech_token->value = NULL;220} else {221nt.u.negTokenResp.responseToken = NULL;222}223224if (mech_buf != GSS_C_NO_BUFFER) {225ret = gss_get_mic(minor_status,226context_handle->negotiated_ctx_id,2270,228mech_buf,229&mech_mic_buf);230if (ret == GSS_S_COMPLETE) {231ALLOC(nt.u.negTokenResp.mechListMIC, 1);232if (nt.u.negTokenResp.mechListMIC == NULL) {233gss_release_buffer(minor_status, &mech_mic_buf);234free_NegotiationToken(&nt);235*minor_status = ENOMEM;236return GSS_S_FAILURE;237}238nt.u.negTokenResp.mechListMIC->length = mech_mic_buf.length;239nt.u.negTokenResp.mechListMIC->data = mech_mic_buf.value;240} else if (ret == GSS_S_UNAVAILABLE) {241nt.u.negTokenResp.mechListMIC = NULL;242} else {243free_NegotiationToken(&nt);244return ret;245}246247} else248nt.u.negTokenResp.mechListMIC = NULL;249250ASN1_MALLOC_ENCODE(NegotiationToken,251output_token->value, output_token->length,252&nt, &size, ret);253if (ret) {254free_NegotiationToken(&nt);255*minor_status = ret;256return GSS_S_FAILURE;257}258259/*260* The response should not be encapsulated, because261* it is a SubsequentContextToken (note though RFC 1964262* specifies encapsulation for all _Kerberos_ tokens).263*/264265if (*(nt.u.negTokenResp.negResult) == accept_completed)266ret = GSS_S_COMPLETE;267else268ret = GSS_S_CONTINUE_NEEDED;269free_NegotiationToken(&nt);270return ret;271}272273274static OM_uint32275verify_mechlist_mic276(OM_uint32 *minor_status,277gssspnego_ctx context_handle,278gss_buffer_t mech_buf,279heim_octet_string *mechListMIC280)281{282OM_uint32 ret;283gss_buffer_desc mic_buf;284285if (context_handle->verified_mic) {286/* This doesn't make sense, we've already verified it? */287*minor_status = 0;288return GSS_S_DUPLICATE_TOKEN;289}290291if (mechListMIC == NULL) {292*minor_status = 0;293return GSS_S_DEFECTIVE_TOKEN;294}295296mic_buf.length = mechListMIC->length;297mic_buf.value = mechListMIC->data;298299ret = gss_verify_mic(minor_status,300context_handle->negotiated_ctx_id,301mech_buf,302&mic_buf,303NULL);304305if (ret != GSS_S_COMPLETE)306ret = GSS_S_DEFECTIVE_TOKEN;307308return ret;309}310311static OM_uint32312select_mech(OM_uint32 *minor_status, MechType *mechType, int verify_p,313gss_OID *mech_p)314{315char mechbuf[64];316size_t mech_len;317gss_OID_desc oid;318gss_OID oidp;319gss_OID_set mechs;320size_t i;321OM_uint32 ret, junk;322323ret = der_put_oid ((unsigned char *)mechbuf + sizeof(mechbuf) - 1,324sizeof(mechbuf),325mechType,326&mech_len);327if (ret) {328return GSS_S_DEFECTIVE_TOKEN;329}330331oid.length = mech_len;332oid.elements = mechbuf + sizeof(mechbuf) - mech_len;333334if (gss_oid_equal(&oid, GSS_SPNEGO_MECHANISM)) {335return GSS_S_BAD_MECH;336}337338*minor_status = 0;339340/* Translate broken MS Kebreros OID */341if (gss_oid_equal(&oid, &_gss_spnego_mskrb_mechanism_oid_desc))342oidp = &_gss_spnego_krb5_mechanism_oid_desc;343else344oidp = &oid;345346347ret = gss_indicate_mechs(&junk, &mechs);348if (ret)349return (ret);350351for (i = 0; i < mechs->count; i++)352if (gss_oid_equal(&mechs->elements[i], oidp))353break;354355if (i == mechs->count) {356gss_release_oid_set(&junk, &mechs);357return GSS_S_BAD_MECH;358}359gss_release_oid_set(&junk, &mechs);360361ret = gss_duplicate_oid(minor_status,362&oid, /* possibly this should be oidp */363mech_p);364365if (verify_p) {366gss_name_t name = GSS_C_NO_NAME;367gss_buffer_desc namebuf;368char *str = NULL, *host, hostname[MAXHOSTNAMELEN];369370host = getenv("GSSAPI_SPNEGO_NAME");371if (host == NULL || issuid()) {372int rv;373if (gethostname(hostname, sizeof(hostname)) != 0) {374*minor_status = errno;375return GSS_S_FAILURE;376}377rv = asprintf(&str, "host@%s", hostname);378if (rv < 0 || str == NULL) {379*minor_status = ENOMEM;380return GSS_S_FAILURE;381}382host = str;383}384385namebuf.length = strlen(host);386namebuf.value = host;387388ret = gss_import_name(minor_status, &namebuf,389GSS_C_NT_HOSTBASED_SERVICE, &name);390if (str)391free(str);392if (ret != GSS_S_COMPLETE)393return ret;394395ret = acceptor_approved(name, *mech_p);396gss_release_name(&junk, &name);397}398399return ret;400}401402403static OM_uint32404acceptor_complete(OM_uint32 * minor_status,405gssspnego_ctx ctx,406int *get_mic,407gss_buffer_t mech_buf,408gss_buffer_t mech_input_token,409gss_buffer_t mech_output_token,410heim_octet_string *mic,411gss_buffer_t output_token)412{413OM_uint32 ret;414int require_mic, verify_mic;415416ret = _gss_spnego_require_mechlist_mic(minor_status, ctx, &require_mic);417if (ret)418return ret;419420ctx->require_mic = require_mic;421422if (mic != NULL)423require_mic = 1;424425if (ctx->open && require_mic) {426if (mech_input_token == GSS_C_NO_BUFFER) { /* Even/One */427verify_mic = 1;428*get_mic = 0;429} else if (mech_output_token != GSS_C_NO_BUFFER &&430mech_output_token->length == 0) { /* Odd */431*get_mic = verify_mic = 1;432} else { /* Even/One */433verify_mic = 0;434*get_mic = 1;435}436437if (verify_mic || *get_mic) {438int eret;439size_t buf_len = 0;440441ASN1_MALLOC_ENCODE(MechTypeList,442mech_buf->value, mech_buf->length,443&ctx->initiator_mech_types, &buf_len, eret);444if (eret) {445*minor_status = eret;446return GSS_S_FAILURE;447}448heim_assert(mech_buf->length == buf_len, "Internal ASN.1 error");449UNREACHABLE(return GSS_S_FAILURE);450}451452if (verify_mic) {453ret = verify_mechlist_mic(minor_status, ctx, mech_buf, mic);454if (ret) {455if (*get_mic)456send_reject (minor_status, output_token);457return ret;458}459ctx->verified_mic = 1;460}461} else462*get_mic = 0;463464return GSS_S_COMPLETE;465}466467468static OM_uint32 GSSAPI_CALLCONV469acceptor_start470(OM_uint32 * minor_status,471gss_ctx_id_t * context_handle,472const gss_cred_id_t acceptor_cred_handle,473const gss_buffer_t input_token_buffer,474const gss_channel_bindings_t input_chan_bindings,475gss_name_t * src_name,476gss_OID * mech_type,477gss_buffer_t output_token,478OM_uint32 * ret_flags,479OM_uint32 * time_rec,480gss_cred_id_t *delegated_cred_handle481)482{483OM_uint32 ret, junk;484NegotiationToken nt;485size_t nt_len;486NegTokenInit *ni;487gss_buffer_desc data;488gss_buffer_t mech_input_token = GSS_C_NO_BUFFER;489gss_buffer_desc mech_output_token;490gss_buffer_desc mech_buf;491gss_OID preferred_mech_type = GSS_C_NO_OID;492gssspnego_ctx ctx;493int get_mic = 0;494int first_ok = 0;495496mech_output_token.value = NULL;497mech_output_token.length = 0;498mech_buf.value = NULL;499500if (input_token_buffer->length == 0)501return send_supported_mechs (minor_status, output_token);502503ret = _gss_spnego_alloc_sec_context(minor_status, context_handle);504if (ret != GSS_S_COMPLETE)505return ret;506507ctx = (gssspnego_ctx)*context_handle;508509/*510* The GSS-API encapsulation is only present on the initial511* context token (negTokenInit).512*/513ret = gss_decapsulate_token (input_token_buffer,514GSS_SPNEGO_MECHANISM,515&data);516if (ret)517return ret;518519ret = decode_NegotiationToken(data.value, data.length, &nt, &nt_len);520gss_release_buffer(minor_status, &data);521if (ret) {522*minor_status = ret;523return GSS_S_DEFECTIVE_TOKEN;524}525if (nt.element != choice_NegotiationToken_negTokenInit) {526*minor_status = 0;527return GSS_S_DEFECTIVE_TOKEN;528}529ni = &nt.u.negTokenInit;530531if (ni->mechTypes.len < 1) {532free_NegotiationToken(&nt);533*minor_status = 0;534return GSS_S_DEFECTIVE_TOKEN;535}536537HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);538539ret = copy_MechTypeList(&ni->mechTypes, &ctx->initiator_mech_types);540if (ret) {541HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);542free_NegotiationToken(&nt);543*minor_status = ret;544return GSS_S_FAILURE;545}546547/*548* First we try the opportunistic token if we have support for it,549* don't try to verify we have credential for the token,550* gss_accept_sec_context() will (hopefully) tell us that.551* If that failes,552*/553554ret = select_mech(minor_status,555&ni->mechTypes.val[0],5560,557&preferred_mech_type);558559if (ret == 0 && ni->mechToken != NULL) {560gss_buffer_desc ibuf;561562ibuf.length = ni->mechToken->length;563ibuf.value = ni->mechToken->data;564mech_input_token = &ibuf;565566if (ctx->mech_src_name != GSS_C_NO_NAME)567gss_release_name(&junk, &ctx->mech_src_name);568569ret = gss_accept_sec_context(minor_status,570&ctx->negotiated_ctx_id,571acceptor_cred_handle,572mech_input_token,573input_chan_bindings,574&ctx->mech_src_name,575&ctx->negotiated_mech_type,576&mech_output_token,577&ctx->mech_flags,578&ctx->mech_time_rec,579delegated_cred_handle);580581if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {582ctx->preferred_mech_type = preferred_mech_type;583if (ret == GSS_S_COMPLETE)584ctx->open = 1;585586ret = acceptor_complete(minor_status,587ctx,588&get_mic,589&mech_buf,590mech_input_token,591&mech_output_token,592ni->mechListMIC,593output_token);594if (ret != GSS_S_COMPLETE)595goto out;596597first_ok = 1;598} else {599gss_mg_collect_error(preferred_mech_type, ret, *minor_status);600}601}602603/*604* If opportunistic token failed, lets try the other mechs.605*/606607if (!first_ok) {608size_t j;609610preferred_mech_type = GSS_C_NO_OID;611612/* Call glue layer to find first mech we support */613for (j = 1; j < ni->mechTypes.len; ++j) {614ret = select_mech(minor_status,615&ni->mechTypes.val[j],6161,617&preferred_mech_type);618if (ret == 0)619break;620}621}622623ctx->preferred_mech_type = preferred_mech_type;624625if (preferred_mech_type == GSS_C_NO_OID) {626send_reject(minor_status, output_token);627HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);628free_NegotiationToken(&nt);629return ret;630}631632/*633* The initial token always have a response634*/635636ret = send_accept (minor_status,637ctx,638&mech_output_token,6391,640get_mic ? &mech_buf : NULL,641output_token);642if (ret)643goto out;644645out:646if (mech_output_token.value != NULL)647gss_release_buffer(&junk, &mech_output_token);648if (mech_buf.value != NULL) {649free(mech_buf.value);650mech_buf.value = NULL;651}652free_NegotiationToken(&nt);653654655if (ret == GSS_S_COMPLETE) {656if (src_name != NULL && ctx->mech_src_name != NULL) {657spnego_name name;658659name = calloc(1, sizeof(*name));660if (name) {661name->mech = ctx->mech_src_name;662ctx->mech_src_name = NULL;663*src_name = (gss_name_t)name;664}665}666}667668if (mech_type != NULL)669*mech_type = ctx->negotiated_mech_type;670if (ret_flags != NULL)671*ret_flags = ctx->mech_flags;672if (time_rec != NULL)673*time_rec = ctx->mech_time_rec;674675if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {676HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);677return ret;678}679680_gss_spnego_internal_delete_sec_context(&junk, context_handle,681GSS_C_NO_BUFFER);682683return ret;684}685686687static OM_uint32 GSSAPI_CALLCONV688acceptor_continue689(OM_uint32 * minor_status,690gss_ctx_id_t * context_handle,691const gss_cred_id_t acceptor_cred_handle,692const gss_buffer_t input_token_buffer,693const gss_channel_bindings_t input_chan_bindings,694gss_name_t * src_name,695gss_OID * mech_type,696gss_buffer_t output_token,697OM_uint32 * ret_flags,698OM_uint32 * time_rec,699gss_cred_id_t *delegated_cred_handle700)701{702OM_uint32 ret, ret2, minor;703NegotiationToken nt;704size_t nt_len;705NegTokenResp *na;706unsigned int negResult = accept_incomplete;707gss_buffer_t mech_input_token = GSS_C_NO_BUFFER;708gss_buffer_t mech_output_token = GSS_C_NO_BUFFER;709gss_buffer_desc mech_buf;710gssspnego_ctx ctx;711712mech_buf.value = NULL;713714ctx = (gssspnego_ctx)*context_handle;715716/*717* The GSS-API encapsulation is only present on the initial718* context token (negTokenInit).719*/720721ret = decode_NegotiationToken(input_token_buffer->value,722input_token_buffer->length,723&nt, &nt_len);724if (ret) {725*minor_status = ret;726return GSS_S_DEFECTIVE_TOKEN;727}728if (nt.element != choice_NegotiationToken_negTokenResp) {729*minor_status = 0;730return GSS_S_DEFECTIVE_TOKEN;731}732na = &nt.u.negTokenResp;733734if (na->negResult != NULL) {735negResult = *(na->negResult);736}737738HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);739740{741gss_buffer_desc ibuf, obuf;742int require_mic, get_mic = 0;743int require_response;744heim_octet_string *mic;745746if (na->responseToken != NULL) {747ibuf.length = na->responseToken->length;748ibuf.value = na->responseToken->data;749mech_input_token = &ibuf;750} else {751ibuf.value = NULL;752ibuf.length = 0;753}754755if (mech_input_token != GSS_C_NO_BUFFER) {756757if (ctx->mech_src_name != GSS_C_NO_NAME)758gss_release_name(&minor, &ctx->mech_src_name);759760ret = gss_accept_sec_context(&minor,761&ctx->negotiated_ctx_id,762acceptor_cred_handle,763mech_input_token,764input_chan_bindings,765&ctx->mech_src_name,766&ctx->negotiated_mech_type,767&obuf,768&ctx->mech_flags,769&ctx->mech_time_rec,770delegated_cred_handle);771772if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {773mech_output_token = &obuf;774}775if (ret != GSS_S_COMPLETE && ret != GSS_S_CONTINUE_NEEDED) {776free_NegotiationToken(&nt);777gss_mg_collect_error(ctx->negotiated_mech_type, ret, minor);778send_reject (minor_status, output_token);779HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);780return ret;781}782if (ret == GSS_S_COMPLETE)783ctx->open = 1;784} else785ret = GSS_S_COMPLETE;786787ret2 = _gss_spnego_require_mechlist_mic(minor_status,788ctx,789&require_mic);790if (ret2)791goto out;792793ctx->require_mic = require_mic;794795mic = na->mechListMIC;796if (mic != NULL)797require_mic = 1;798799if (ret == GSS_S_COMPLETE)800ret = acceptor_complete(minor_status,801ctx,802&get_mic,803&mech_buf,804mech_input_token,805mech_output_token,806na->mechListMIC,807output_token);808809if (ctx->mech_flags & GSS_C_DCE_STYLE)810require_response = (negResult != accept_completed);811else812require_response = 0;813814/*815* Check whether we need to send a result: there should be only816* one accept_completed response sent in the entire negotiation817*/818if ((mech_output_token != GSS_C_NO_BUFFER &&819mech_output_token->length != 0)820|| (ctx->open && negResult == accept_incomplete)821|| require_response822|| get_mic) {823ret2 = send_accept (minor_status,824ctx,825mech_output_token,8260,827get_mic ? &mech_buf : NULL,828output_token);829if (ret2)830goto out;831}832833out:834if (ret2 != GSS_S_COMPLETE)835ret = ret2;836if (mech_output_token != NULL)837gss_release_buffer(&minor, mech_output_token);838if (mech_buf.value != NULL)839free(mech_buf.value);840free_NegotiationToken(&nt);841}842843if (ret == GSS_S_COMPLETE) {844if (src_name != NULL && ctx->mech_src_name != NULL) {845spnego_name name;846847name = calloc(1, sizeof(*name));848if (name) {849name->mech = ctx->mech_src_name;850ctx->mech_src_name = NULL;851*src_name = (gss_name_t)name;852}853}854}855856if (mech_type != NULL)857*mech_type = ctx->negotiated_mech_type;858if (ret_flags != NULL)859*ret_flags = ctx->mech_flags;860if (time_rec != NULL)861*time_rec = ctx->mech_time_rec;862863if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {864HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);865return ret;866}867868_gss_spnego_internal_delete_sec_context(&minor, context_handle,869GSS_C_NO_BUFFER);870871return ret;872}873874OM_uint32 GSSAPI_CALLCONV875_gss_spnego_accept_sec_context876(OM_uint32 * minor_status,877gss_ctx_id_t * context_handle,878const gss_cred_id_t acceptor_cred_handle,879const gss_buffer_t input_token_buffer,880const gss_channel_bindings_t input_chan_bindings,881gss_name_t * src_name,882gss_OID * mech_type,883gss_buffer_t output_token,884OM_uint32 * ret_flags,885OM_uint32 * time_rec,886gss_cred_id_t *delegated_cred_handle887)888{889_gss_accept_sec_context_t *func;890891*minor_status = 0;892893output_token->length = 0;894output_token->value = NULL;895896if (src_name != NULL)897*src_name = GSS_C_NO_NAME;898if (mech_type != NULL)899*mech_type = GSS_C_NO_OID;900if (ret_flags != NULL)901*ret_flags = 0;902if (time_rec != NULL)903*time_rec = 0;904if (delegated_cred_handle != NULL)905*delegated_cred_handle = GSS_C_NO_CREDENTIAL;906907908if (*context_handle == GSS_C_NO_CONTEXT)909func = acceptor_start;910else911func = acceptor_continue;912913914return (*func)(minor_status, context_handle, acceptor_cred_handle,915input_token_buffer, input_chan_bindings,916src_name, mech_type, output_token, ret_flags,917time_rec, delegated_cred_handle);918}919920921