Path: blob/main/crypto/heimdal/lib/gssapi/krb5/accept_sec_context.c
34923 views
/*1* Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan2* (Royal Institute of Technology, Stockholm, Sweden).3* All rights reserved.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 "gsskrb5_locl.h"3435HEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER;36krb5_keytab _gsskrb5_keytab;3738static krb5_error_code39validate_keytab(krb5_context context, const char *name, krb5_keytab *id)40{41krb5_error_code ret;4243ret = krb5_kt_resolve(context, name, id);44if (ret)45return ret;4647ret = krb5_kt_have_content(context, *id);48if (ret) {49krb5_kt_close(context, *id);50*id = NULL;51}5253return ret;54}5556OM_uint3257_gsskrb5_register_acceptor_identity(OM_uint32 *min_stat, const char *identity)58{59krb5_context context;60krb5_error_code ret;6162*min_stat = 0;6364ret = _gsskrb5_init(&context);65if(ret)66return GSS_S_FAILURE;6768HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);6970if(_gsskrb5_keytab != NULL) {71krb5_kt_close(context, _gsskrb5_keytab);72_gsskrb5_keytab = NULL;73}74if (identity == NULL) {75ret = krb5_kt_default(context, &_gsskrb5_keytab);76} else {77/*78* First check if we can the keytab as is and if it has content...79*/80ret = validate_keytab(context, identity, &_gsskrb5_keytab);81/*82* if it doesn't, lets prepend FILE: and try again83*/84if (ret) {85char *p = NULL;86ret = asprintf(&p, "FILE:%s", identity);87if(ret < 0 || p == NULL) {88HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);89return GSS_S_FAILURE;90}91ret = validate_keytab(context, p, &_gsskrb5_keytab);92free(p);93}94}95HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);96if(ret) {97*min_stat = ret;98return GSS_S_FAILURE;99}100return GSS_S_COMPLETE;101}102103void104_gsskrb5i_is_cfx(krb5_context context, gsskrb5_ctx ctx, int acceptor)105{106krb5_error_code ret;107krb5_keyblock *key;108109if (acceptor) {110if (ctx->auth_context->local_subkey)111key = ctx->auth_context->local_subkey;112else113key = ctx->auth_context->remote_subkey;114} else {115if (ctx->auth_context->remote_subkey)116key = ctx->auth_context->remote_subkey;117else118key = ctx->auth_context->local_subkey;119}120if (key == NULL)121key = ctx->auth_context->keyblock;122123if (key == NULL)124return;125126switch (key->keytype) {127case ETYPE_DES_CBC_CRC:128case ETYPE_DES_CBC_MD4:129case ETYPE_DES_CBC_MD5:130case ETYPE_DES3_CBC_MD5:131case ETYPE_OLD_DES3_CBC_SHA1:132case ETYPE_DES3_CBC_SHA1:133case ETYPE_ARCFOUR_HMAC_MD5:134case ETYPE_ARCFOUR_HMAC_MD5_56:135break;136default :137ctx->more_flags |= IS_CFX;138139if ((acceptor && ctx->auth_context->local_subkey) ||140(!acceptor && ctx->auth_context->remote_subkey))141ctx->more_flags |= ACCEPTOR_SUBKEY;142break;143}144if (ctx->crypto)145krb5_crypto_destroy(context, ctx->crypto);146ret = krb5_crypto_init(context, key, 0, &ctx->crypto);147}148149150static OM_uint32151gsskrb5_accept_delegated_token152(OM_uint32 * minor_status,153gsskrb5_ctx ctx,154krb5_context context,155gss_cred_id_t * delegated_cred_handle156)157{158krb5_ccache ccache = NULL;159krb5_error_code kret;160int32_t ac_flags, ret = GSS_S_COMPLETE;161162*minor_status = 0;163164/* XXX Create a new delegated_cred_handle? */165if (delegated_cred_handle == NULL) {166kret = krb5_cc_default (context, &ccache);167} else {168*delegated_cred_handle = NULL;169kret = krb5_cc_new_unique (context, krb5_cc_type_memory,170NULL, &ccache);171}172if (kret) {173ctx->flags &= ~GSS_C_DELEG_FLAG;174goto out;175}176177kret = krb5_cc_initialize(context, ccache, ctx->source);178if (kret) {179ctx->flags &= ~GSS_C_DELEG_FLAG;180goto out;181}182183krb5_auth_con_removeflags(context,184ctx->auth_context,185KRB5_AUTH_CONTEXT_DO_TIME,186&ac_flags);187kret = krb5_rd_cred2(context,188ctx->auth_context,189ccache,190&ctx->fwd_data);191krb5_auth_con_setflags(context,192ctx->auth_context,193ac_flags);194if (kret) {195ctx->flags &= ~GSS_C_DELEG_FLAG;196ret = GSS_S_FAILURE;197*minor_status = kret;198goto out;199}200201if (delegated_cred_handle) {202gsskrb5_cred handle;203204ret = _gsskrb5_krb5_import_cred(minor_status,205ccache,206NULL,207NULL,208delegated_cred_handle);209if (ret != GSS_S_COMPLETE)210goto out;211212handle = (gsskrb5_cred) *delegated_cred_handle;213214handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;215krb5_cc_close(context, ccache);216ccache = NULL;217}218219out:220if (ccache) {221/* Don't destroy the default cred cache */222if (delegated_cred_handle == NULL)223krb5_cc_close(context, ccache);224else225krb5_cc_destroy(context, ccache);226}227return ret;228}229230static OM_uint32231gsskrb5_acceptor_ready(OM_uint32 * minor_status,232gsskrb5_ctx ctx,233krb5_context context,234gss_cred_id_t *delegated_cred_handle)235{236OM_uint32 ret;237int32_t seq_number;238int is_cfx = 0;239240krb5_auth_con_getremoteseqnumber (context,241ctx->auth_context,242&seq_number);243244_gsskrb5i_is_cfx(context, ctx, 1);245is_cfx = (ctx->more_flags & IS_CFX);246247ret = _gssapi_msg_order_create(minor_status,248&ctx->order,249_gssapi_msg_order_f(ctx->flags),250seq_number, 0, is_cfx);251if (ret)252return ret;253254/*255* If requested, set local sequence num to remote sequence if this256* isn't a mutual authentication context257*/258if (!(ctx->flags & GSS_C_MUTUAL_FLAG) && _gssapi_msg_order_f(ctx->flags)) {259krb5_auth_con_setlocalseqnumber(context,260ctx->auth_context,261seq_number);262}263264/*265* We should handle the delegation ticket, in case it's there266*/267if (ctx->fwd_data.length > 0 && (ctx->flags & GSS_C_DELEG_FLAG)) {268ret = gsskrb5_accept_delegated_token(minor_status,269ctx,270context,271delegated_cred_handle);272if (ret)273return ret;274} else {275/* Well, looks like it wasn't there after all */276ctx->flags &= ~GSS_C_DELEG_FLAG;277}278279ctx->state = ACCEPTOR_READY;280ctx->more_flags |= OPEN;281282return GSS_S_COMPLETE;283}284285static OM_uint32286send_error_token(OM_uint32 *minor_status,287krb5_context context,288krb5_error_code kret,289krb5_principal server,290krb5_data *indata,291gss_buffer_t output_token)292{293krb5_principal ap_req_server = NULL;294krb5_error_code ret;295krb5_data outbuf;296/* this e_data value encodes KERB_AP_ERR_TYPE_SKEW_RECOVERY which297tells windows to try again with the corrected timestamp. See298[MS-KILE] 2.2.1 KERB-ERROR-DATA */299krb5_data e_data = { 7, rk_UNCONST("\x30\x05\xa1\x03\x02\x01\x02") };300301/* build server from request if the acceptor had not selected one */302if (server == NULL) {303AP_REQ ap_req;304305ret = krb5_decode_ap_req(context, indata, &ap_req);306if (ret) {307*minor_status = ret;308return GSS_S_FAILURE;309}310ret = _krb5_principalname2krb5_principal(context,311&ap_req_server,312ap_req.ticket.sname,313ap_req.ticket.realm);314free_AP_REQ(&ap_req);315if (ret) {316*minor_status = ret;317return GSS_S_FAILURE;318}319server = ap_req_server;320}321322ret = krb5_mk_error(context, kret, NULL, &e_data, NULL,323server, NULL, NULL, &outbuf);324if (ap_req_server)325krb5_free_principal(context, ap_req_server);326if (ret) {327*minor_status = ret;328return GSS_S_FAILURE;329}330331ret = _gsskrb5_encapsulate(minor_status,332&outbuf,333output_token,334"\x03\x00",335GSS_KRB5_MECHANISM);336krb5_data_free (&outbuf);337if (ret)338return ret;339340*minor_status = 0;341return GSS_S_CONTINUE_NEEDED;342}343344345static OM_uint32346gsskrb5_acceptor_start(OM_uint32 * minor_status,347gsskrb5_ctx ctx,348krb5_context context,349const gss_cred_id_t acceptor_cred_handle,350const gss_buffer_t input_token_buffer,351const gss_channel_bindings_t input_chan_bindings,352gss_name_t * src_name,353gss_OID * mech_type,354gss_buffer_t output_token,355OM_uint32 * ret_flags,356OM_uint32 * time_rec,357gss_cred_id_t * delegated_cred_handle)358{359krb5_error_code kret;360OM_uint32 ret = GSS_S_COMPLETE;361krb5_data indata;362krb5_flags ap_options;363krb5_keytab keytab = NULL;364int is_cfx = 0;365const gsskrb5_cred acceptor_cred = (gsskrb5_cred)acceptor_cred_handle;366367/*368* We may, or may not, have an escapsulation.369*/370ret = _gsskrb5_decapsulate (minor_status,371input_token_buffer,372&indata,373"\x01\x00",374GSS_KRB5_MECHANISM);375376if (ret) {377/* Assume that there is no OID wrapping. */378indata.length = input_token_buffer->length;379indata.data = input_token_buffer->value;380}381382/*383* We need to get our keytab384*/385if (acceptor_cred == NULL) {386if (_gsskrb5_keytab != NULL)387keytab = _gsskrb5_keytab;388} else if (acceptor_cred->keytab != NULL) {389keytab = acceptor_cred->keytab;390}391392/*393* We need to check the ticket and create the AP-REP packet394*/395396{397krb5_rd_req_in_ctx in = NULL;398krb5_rd_req_out_ctx out = NULL;399krb5_principal server = NULL;400401if (acceptor_cred)402server = acceptor_cred->principal;403404kret = krb5_rd_req_in_ctx_alloc(context, &in);405if (kret == 0)406kret = krb5_rd_req_in_set_keytab(context, in, keytab);407if (kret) {408if (in)409krb5_rd_req_in_ctx_free(context, in);410*minor_status = kret;411return GSS_S_FAILURE;412}413414kret = krb5_rd_req_ctx(context,415&ctx->auth_context,416&indata,417server,418in, &out);419krb5_rd_req_in_ctx_free(context, in);420if (kret == KRB5KRB_AP_ERR_SKEW || kret == KRB5KRB_AP_ERR_TKT_NYV) {421/*422* No reply in non-MUTUAL mode, but we don't know that its423* non-MUTUAL mode yet, thats inside the 8003 checksum, so424* lets only send the error token on clock skew, that425* limit when send error token for non-MUTUAL.426*/427free_Authenticator(ctx->auth_context->authenticator);428return send_error_token(minor_status, context, kret,429server, &indata, output_token);430} else if (kret) {431*minor_status = kret;432return GSS_S_FAILURE;433}434435/*436* we need to remember some data on the context_handle.437*/438kret = krb5_rd_req_out_get_ap_req_options(context, out,439&ap_options);440if (kret == 0)441kret = krb5_rd_req_out_get_ticket(context, out,442&ctx->ticket);443if (kret == 0)444kret = krb5_rd_req_out_get_keyblock(context, out,445&ctx->service_keyblock);446ctx->lifetime = ctx->ticket->ticket.endtime;447448krb5_rd_req_out_ctx_free(context, out);449if (kret) {450ret = GSS_S_FAILURE;451*minor_status = kret;452return ret;453}454}455456457/*458* We need to copy the principal names to the context and the459* calling layer.460*/461kret = krb5_copy_principal(context,462ctx->ticket->client,463&ctx->source);464if (kret) {465ret = GSS_S_FAILURE;466*minor_status = kret;467}468469kret = krb5_copy_principal(context,470ctx->ticket->server,471&ctx->target);472if (kret) {473ret = GSS_S_FAILURE;474*minor_status = kret;475return ret;476}477478/*479* We need to setup some compat stuff, this assumes that480* context_handle->target is already set.481*/482ret = _gss_DES3_get_mic_compat(minor_status, ctx, context);483if (ret)484return ret;485486if (src_name != NULL) {487kret = krb5_copy_principal (context,488ctx->ticket->client,489(gsskrb5_name*)src_name);490if (kret) {491ret = GSS_S_FAILURE;492*minor_status = kret;493return ret;494}495}496497/*498* We need to get the flags out of the 8003 checksum.499*/500501{502krb5_authenticator authenticator;503504kret = krb5_auth_con_getauthenticator(context,505ctx->auth_context,506&authenticator);507if(kret) {508ret = GSS_S_FAILURE;509*minor_status = kret;510return ret;511}512513if (authenticator->cksum == NULL) {514krb5_free_authenticator(context, &authenticator);515*minor_status = 0;516return GSS_S_BAD_BINDINGS;517}518519if (authenticator->cksum->cksumtype == CKSUMTYPE_GSSAPI) {520ret = _gsskrb5_verify_8003_checksum(minor_status,521input_chan_bindings,522authenticator->cksum,523&ctx->flags,524&ctx->fwd_data);525526krb5_free_authenticator(context, &authenticator);527if (ret) {528return ret;529}530} else {531krb5_crypto crypto;532533kret = krb5_crypto_init(context,534ctx->auth_context->keyblock,5350, &crypto);536if(kret) {537krb5_free_authenticator(context, &authenticator);538539ret = GSS_S_FAILURE;540*minor_status = kret;541return ret;542}543544/*545* Windows accepts Samba3's use of a kerberos, rather than546* GSSAPI checksum here547*/548549kret = krb5_verify_checksum(context,550crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0,551authenticator->cksum);552krb5_free_authenticator(context, &authenticator);553krb5_crypto_destroy(context, crypto);554555if(kret) {556ret = GSS_S_BAD_SIG;557*minor_status = kret;558return ret;559}560561/*562* Samba style get some flags (but not DCE-STYLE), use563* ap_options to guess the mutual flag.564*/565ctx->flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;566if (ap_options & AP_OPTS_MUTUAL_REQUIRED)567ctx->flags |= GSS_C_MUTUAL_FLAG;568}569}570571if(ctx->flags & GSS_C_MUTUAL_FLAG) {572krb5_data outbuf;573int use_subkey = 0;574575_gsskrb5i_is_cfx(context, ctx, 1);576is_cfx = (ctx->more_flags & IS_CFX);577578if (is_cfx || (ap_options & AP_OPTS_USE_SUBKEY)) {579use_subkey = 1;580} else {581krb5_keyblock *rkey;582583/*584* If there is a initiator subkey, copy that to acceptor585* subkey to match Windows behavior586*/587kret = krb5_auth_con_getremotesubkey(context,588ctx->auth_context,589&rkey);590if (kret == 0) {591kret = krb5_auth_con_setlocalsubkey(context,592ctx->auth_context,593rkey);594if (kret == 0)595use_subkey = 1;596krb5_free_keyblock(context, rkey);597}598}599if (use_subkey) {600ctx->more_flags |= ACCEPTOR_SUBKEY;601krb5_auth_con_addflags(context, ctx->auth_context,602KRB5_AUTH_CONTEXT_USE_SUBKEY,603NULL);604}605606kret = krb5_mk_rep(context,607ctx->auth_context,608&outbuf);609if (kret) {610*minor_status = kret;611return GSS_S_FAILURE;612}613614if (IS_DCE_STYLE(ctx)) {615output_token->length = outbuf.length;616output_token->value = outbuf.data;617} else {618ret = _gsskrb5_encapsulate(minor_status,619&outbuf,620output_token,621"\x02\x00",622GSS_KRB5_MECHANISM);623krb5_data_free (&outbuf);624if (ret)625return ret;626}627}628629ctx->flags |= GSS_C_TRANS_FLAG;630631/* Remember the flags */632633ctx->lifetime = ctx->ticket->ticket.endtime;634ctx->more_flags |= OPEN;635636if (mech_type)637*mech_type = GSS_KRB5_MECHANISM;638639if (time_rec) {640ret = _gsskrb5_lifetime_left(minor_status,641context,642ctx->lifetime,643time_rec);644if (ret) {645return ret;646}647}648649/*650* When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from651* the client.652*/653if (IS_DCE_STYLE(ctx)) {654/*655* Return flags to caller, but we haven't processed656* delgations yet657*/658if (ret_flags)659*ret_flags = (ctx->flags & ~GSS_C_DELEG_FLAG);660661ctx->state = ACCEPTOR_WAIT_FOR_DCESTYLE;662return GSS_S_CONTINUE_NEEDED;663}664665ret = gsskrb5_acceptor_ready(minor_status, ctx, context,666delegated_cred_handle);667668if (ret_flags)669*ret_flags = ctx->flags;670671return ret;672}673674static OM_uint32675acceptor_wait_for_dcestyle(OM_uint32 * minor_status,676gsskrb5_ctx ctx,677krb5_context context,678const gss_cred_id_t acceptor_cred_handle,679const gss_buffer_t input_token_buffer,680const gss_channel_bindings_t input_chan_bindings,681gss_name_t * src_name,682gss_OID * mech_type,683gss_buffer_t output_token,684OM_uint32 * ret_flags,685OM_uint32 * time_rec,686gss_cred_id_t * delegated_cred_handle)687{688OM_uint32 ret;689krb5_error_code kret;690krb5_data inbuf;691int32_t r_seq_number, l_seq_number;692693/*694* We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP695*/696697inbuf.length = input_token_buffer->length;698inbuf.data = input_token_buffer->value;699700/*701* We need to remeber the old remote seq_number, then check if the702* client has replied with our local seq_number, and then reset703* the remote seq_number to the old value704*/705{706kret = krb5_auth_con_getlocalseqnumber(context,707ctx->auth_context,708&l_seq_number);709if (kret) {710*minor_status = kret;711return GSS_S_FAILURE;712}713714kret = krb5_auth_con_getremoteseqnumber(context,715ctx->auth_context,716&r_seq_number);717if (kret) {718*minor_status = kret;719return GSS_S_FAILURE;720}721722kret = krb5_auth_con_setremoteseqnumber(context,723ctx->auth_context,724l_seq_number);725if (kret) {726*minor_status = kret;727return GSS_S_FAILURE;728}729}730731/*732* We need to verify the AP_REP, but we need to flag that this is733* DCE_STYLE, so don't check the timestamps this time, but put the734* flag DO_TIME back afterward.735*/736{737krb5_ap_rep_enc_part *repl;738int32_t auth_flags;739740krb5_auth_con_removeflags(context,741ctx->auth_context,742KRB5_AUTH_CONTEXT_DO_TIME,743&auth_flags);744745kret = krb5_rd_rep(context, ctx->auth_context, &inbuf, &repl);746if (kret) {747*minor_status = kret;748return GSS_S_FAILURE;749}750krb5_free_ap_rep_enc_part(context, repl);751krb5_auth_con_setflags(context, ctx->auth_context, auth_flags);752}753754/* We need to check the liftime */755{756OM_uint32 lifetime_rec;757758ret = _gsskrb5_lifetime_left(minor_status,759context,760ctx->lifetime,761&lifetime_rec);762if (ret) {763return ret;764}765if (lifetime_rec == 0) {766return GSS_S_CONTEXT_EXPIRED;767}768769if (time_rec) *time_rec = lifetime_rec;770}771772/* We need to give the caller the flags which are in use */773if (ret_flags) *ret_flags = ctx->flags;774775if (src_name) {776kret = krb5_copy_principal(context,777ctx->source,778(gsskrb5_name*)src_name);779if (kret) {780*minor_status = kret;781return GSS_S_FAILURE;782}783}784785/*786* After the krb5_rd_rep() the remote and local seq_number should787* be the same, because the client just replies the seq_number788* from our AP-REP in its AP-REP, but then the client uses the789* seq_number from its AP-REQ for GSS_wrap()790*/791{792int32_t tmp_r_seq_number, tmp_l_seq_number;793794kret = krb5_auth_con_getremoteseqnumber(context,795ctx->auth_context,796&tmp_r_seq_number);797if (kret) {798*minor_status = kret;799return GSS_S_FAILURE;800}801802kret = krb5_auth_con_getlocalseqnumber(context,803ctx->auth_context,804&tmp_l_seq_number);805if (kret) {806807*minor_status = kret;808return GSS_S_FAILURE;809}810811/*812* Here we check if the client has responsed with our local seq_number,813*/814if (tmp_r_seq_number != tmp_l_seq_number) {815return GSS_S_UNSEQ_TOKEN;816}817}818819/*820* We need to reset the remote seq_number, because the client will use,821* the old one for the GSS_wrap() calls822*/823{824kret = krb5_auth_con_setremoteseqnumber(context,825ctx->auth_context,826r_seq_number);827if (kret) {828*minor_status = kret;829return GSS_S_FAILURE;830}831}832833return gsskrb5_acceptor_ready(minor_status, ctx, context,834delegated_cred_handle);835}836837838OM_uint32 GSSAPI_CALLCONV839_gsskrb5_accept_sec_context(OM_uint32 * minor_status,840gss_ctx_id_t * context_handle,841const gss_cred_id_t acceptor_cred_handle,842const gss_buffer_t input_token_buffer,843const gss_channel_bindings_t input_chan_bindings,844gss_name_t * src_name,845gss_OID * mech_type,846gss_buffer_t output_token,847OM_uint32 * ret_flags,848OM_uint32 * time_rec,849gss_cred_id_t * delegated_cred_handle)850{851krb5_context context;852OM_uint32 ret;853gsskrb5_ctx ctx;854855GSSAPI_KRB5_INIT(&context);856857output_token->length = 0;858output_token->value = NULL;859860if (src_name != NULL)861*src_name = NULL;862if (mech_type)863*mech_type = GSS_KRB5_MECHANISM;864865if (*context_handle == GSS_C_NO_CONTEXT) {866ret = _gsskrb5_create_ctx(minor_status,867context_handle,868context,869input_chan_bindings,870ACCEPTOR_START);871if (ret)872return ret;873}874875ctx = (gsskrb5_ctx)*context_handle;876877878/*879* TODO: check the channel_bindings880* (above just sets them to krb5 layer)881*/882883HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);884885switch (ctx->state) {886case ACCEPTOR_START:887ret = gsskrb5_acceptor_start(minor_status,888ctx,889context,890acceptor_cred_handle,891input_token_buffer,892input_chan_bindings,893src_name,894mech_type,895output_token,896ret_flags,897time_rec,898delegated_cred_handle);899break;900case ACCEPTOR_WAIT_FOR_DCESTYLE:901ret = acceptor_wait_for_dcestyle(minor_status,902ctx,903context,904acceptor_cred_handle,905input_token_buffer,906input_chan_bindings,907src_name,908mech_type,909output_token,910ret_flags,911time_rec,912delegated_cred_handle);913break;914case ACCEPTOR_READY:915/*916* If we get there, the caller have called917* gss_accept_sec_context() one time too many.918*/919ret = GSS_S_BAD_STATUS;920break;921default:922/* TODO: is this correct here? --metze */923ret = GSS_S_BAD_STATUS;924break;925}926927HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);928929if (GSS_ERROR(ret)) {930OM_uint32 min2;931_gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER);932}933934return ret;935}936937938