Path: blob/main/crypto/heimdal/lib/gssapi/krb5/init_sec_context.c
34923 views
/*1* Copyright (c) 1997 - 2008 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"3435/*36* copy the addresses from `input_chan_bindings' (if any) to37* the auth context `ac'38*/3940static OM_uint3241set_addresses (krb5_context context,42krb5_auth_context ac,43const gss_channel_bindings_t input_chan_bindings)44{45/* Port numbers are expected to be in application_data.value,46* initator's port first */4748krb5_address initiator_addr, acceptor_addr;49krb5_error_code kret;5051if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS52|| input_chan_bindings->application_data.length !=532 * sizeof(ac->local_port))54return 0;5556memset(&initiator_addr, 0, sizeof(initiator_addr));57memset(&acceptor_addr, 0, sizeof(acceptor_addr));5859ac->local_port =60*(int16_t *) input_chan_bindings->application_data.value;6162ac->remote_port =63*((int16_t *) input_chan_bindings->application_data.value + 1);6465kret = _gsskrb5i_address_to_krb5addr(context,66input_chan_bindings->acceptor_addrtype,67&input_chan_bindings->acceptor_address,68ac->remote_port,69&acceptor_addr);70if (kret)71return kret;7273kret = _gsskrb5i_address_to_krb5addr(context,74input_chan_bindings->initiator_addrtype,75&input_chan_bindings->initiator_address,76ac->local_port,77&initiator_addr);78if (kret) {79krb5_free_address (context, &acceptor_addr);80return kret;81}8283kret = krb5_auth_con_setaddrs(context,84ac,85&initiator_addr, /* local address */86&acceptor_addr); /* remote address */8788krb5_free_address (context, &initiator_addr);89krb5_free_address (context, &acceptor_addr);9091#if 092free(input_chan_bindings->application_data.value);93input_chan_bindings->application_data.value = NULL;94input_chan_bindings->application_data.length = 0;95#endif9697return kret;98}99100OM_uint32101_gsskrb5_create_ctx(102OM_uint32 * minor_status,103gss_ctx_id_t * context_handle,104krb5_context context,105const gss_channel_bindings_t input_chan_bindings,106enum gss_ctx_id_t_state state)107{108krb5_error_code kret;109gsskrb5_ctx ctx;110111*context_handle = NULL;112113ctx = malloc(sizeof(*ctx));114if (ctx == NULL) {115*minor_status = ENOMEM;116return GSS_S_FAILURE;117}118ctx->auth_context = NULL;119ctx->deleg_auth_context = NULL;120ctx->source = NULL;121ctx->target = NULL;122ctx->kcred = NULL;123ctx->ccache = NULL;124ctx->state = state;125ctx->flags = 0;126ctx->more_flags = 0;127ctx->service_keyblock = NULL;128ctx->ticket = NULL;129krb5_data_zero(&ctx->fwd_data);130ctx->lifetime = GSS_C_INDEFINITE;131ctx->order = NULL;132ctx->crypto = NULL;133HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex);134135kret = krb5_auth_con_init (context, &ctx->auth_context);136if (kret) {137*minor_status = kret;138HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);139return GSS_S_FAILURE;140}141142kret = krb5_auth_con_init (context, &ctx->deleg_auth_context);143if (kret) {144*minor_status = kret;145krb5_auth_con_free(context, ctx->auth_context);146HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);147return GSS_S_FAILURE;148}149150kret = set_addresses(context, ctx->auth_context, input_chan_bindings);151if (kret) {152*minor_status = kret;153154krb5_auth_con_free(context, ctx->auth_context);155krb5_auth_con_free(context, ctx->deleg_auth_context);156157HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);158159return GSS_S_BAD_BINDINGS;160}161162kret = set_addresses(context, ctx->deleg_auth_context, input_chan_bindings);163if (kret) {164*minor_status = kret;165166krb5_auth_con_free(context, ctx->auth_context);167krb5_auth_con_free(context, ctx->deleg_auth_context);168169HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);170171return GSS_S_BAD_BINDINGS;172}173174/*175* We need a sequence number176*/177178krb5_auth_con_addflags(context,179ctx->auth_context,180KRB5_AUTH_CONTEXT_DO_SEQUENCE |181KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED,182NULL);183184/*185* We need a sequence number186*/187188krb5_auth_con_addflags(context,189ctx->deleg_auth_context,190KRB5_AUTH_CONTEXT_DO_SEQUENCE |191KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED,192NULL);193194*context_handle = (gss_ctx_id_t)ctx;195196return GSS_S_COMPLETE;197}198199200static OM_uint32201gsskrb5_get_creds(202OM_uint32 * minor_status,203krb5_context context,204krb5_ccache ccache,205gsskrb5_ctx ctx,206const gss_name_t target_name,207int use_dns,208OM_uint32 time_req,209OM_uint32 * time_rec)210{211OM_uint32 ret;212krb5_error_code kret;213krb5_creds this_cred;214OM_uint32 lifetime_rec;215216if (ctx->target) {217krb5_free_principal(context, ctx->target);218ctx->target = NULL;219}220if (ctx->kcred) {221krb5_free_creds(context, ctx->kcred);222ctx->kcred = NULL;223}224225ret = _gsskrb5_canon_name(minor_status, context, use_dns,226ctx->source, target_name, &ctx->target);227if (ret)228return ret;229230memset(&this_cred, 0, sizeof(this_cred));231this_cred.client = ctx->source;232this_cred.server = ctx->target;233234if (time_req && time_req != GSS_C_INDEFINITE) {235krb5_timestamp ts;236237krb5_timeofday (context, &ts);238this_cred.times.endtime = ts + time_req;239} else {240this_cred.times.endtime = 0;241}242243this_cred.session.keytype = KEYTYPE_NULL;244245kret = krb5_get_credentials(context,2460,247ccache,248&this_cred,249&ctx->kcred);250if (kret) {251*minor_status = kret;252return GSS_S_FAILURE;253}254255ctx->lifetime = ctx->kcred->times.endtime;256257ret = _gsskrb5_lifetime_left(minor_status, context,258ctx->lifetime, &lifetime_rec);259if (ret) return ret;260261if (lifetime_rec == 0) {262*minor_status = 0;263return GSS_S_CONTEXT_EXPIRED;264}265266if (time_rec) *time_rec = lifetime_rec;267268return GSS_S_COMPLETE;269}270271static OM_uint32272gsskrb5_initiator_ready(273OM_uint32 * minor_status,274gsskrb5_ctx ctx,275krb5_context context)276{277OM_uint32 ret;278int32_t seq_number;279int is_cfx = 0;280OM_uint32 flags = ctx->flags;281282krb5_free_creds(context, ctx->kcred);283ctx->kcred = NULL;284285if (ctx->more_flags & CLOSE_CCACHE)286krb5_cc_close(context, ctx->ccache);287ctx->ccache = NULL;288289krb5_auth_con_getremoteseqnumber (context, ctx->auth_context, &seq_number);290291_gsskrb5i_is_cfx(context, ctx, 0);292is_cfx = (ctx->more_flags & IS_CFX);293294ret = _gssapi_msg_order_create(minor_status,295&ctx->order,296_gssapi_msg_order_f(flags),297seq_number, 0, is_cfx);298if (ret) return ret;299300ctx->state = INITIATOR_READY;301ctx->more_flags |= OPEN;302303return GSS_S_COMPLETE;304}305306/*307* handle delegated creds in init-sec-context308*/309310static void311do_delegation (krb5_context context,312krb5_auth_context ac,313krb5_ccache ccache,314krb5_creds *cred,315krb5_const_principal name,316krb5_data *fwd_data,317uint32_t flagmask,318uint32_t *flags)319{320krb5_creds creds;321KDCOptions fwd_flags;322krb5_error_code kret;323324memset (&creds, 0, sizeof(creds));325krb5_data_zero (fwd_data);326327kret = krb5_cc_get_principal(context, ccache, &creds.client);328if (kret)329goto out;330331kret = krb5_make_principal(context,332&creds.server,333creds.client->realm,334KRB5_TGS_NAME,335creds.client->realm,336NULL);337if (kret)338goto out;339340creds.times.endtime = 0;341342memset(&fwd_flags, 0, sizeof(fwd_flags));343fwd_flags.forwarded = 1;344fwd_flags.forwardable = 1;345346if ( /*target_name->name.name_type != KRB5_NT_SRV_HST ||*/347name->name.name_string.len < 2)348goto out;349350kret = krb5_get_forwarded_creds(context,351ac,352ccache,353KDCOptions2int(fwd_flags),354name->name.name_string.val[1],355&creds,356fwd_data);357358out:359if (kret)360*flags &= ~flagmask;361else362*flags |= flagmask;363364if (creds.client)365krb5_free_principal(context, creds.client);366if (creds.server)367krb5_free_principal(context, creds.server);368}369370/*371* first stage of init-sec-context372*/373374static OM_uint32375init_auth376(OM_uint32 * minor_status,377gsskrb5_cred cred,378gsskrb5_ctx ctx,379krb5_context context,380gss_name_t name,381const gss_OID mech_type,382OM_uint32 req_flags,383OM_uint32 time_req,384const gss_buffer_t input_token,385gss_OID * actual_mech_type,386gss_buffer_t output_token,387OM_uint32 * ret_flags,388OM_uint32 * time_rec389)390{391OM_uint32 ret = GSS_S_FAILURE;392krb5_error_code kret;393krb5_data outbuf;394krb5_data fwd_data;395OM_uint32 lifetime_rec;396int allow_dns = 1;397398krb5_data_zero(&outbuf);399krb5_data_zero(&fwd_data);400401*minor_status = 0;402403if (actual_mech_type)404*actual_mech_type = GSS_KRB5_MECHANISM;405406if (cred == NULL) {407kret = krb5_cc_default (context, &ctx->ccache);408if (kret) {409*minor_status = kret;410ret = GSS_S_FAILURE;411goto failure;412}413ctx->more_flags |= CLOSE_CCACHE;414} else415ctx->ccache = cred->ccache;416417kret = krb5_cc_get_principal (context, ctx->ccache, &ctx->source);418if (kret) {419*minor_status = kret;420ret = GSS_S_FAILURE;421goto failure;422}423424/*425* This is hideous glue for (NFS) clients that wants to limit the426* available enctypes to what it can support (encryption in427* kernel). If there is no enctypes selected for this credential,428* reset it to the default set of enctypes.429*/430{431krb5_enctype *enctypes = NULL;432433if (cred && cred->enctypes)434enctypes = cred->enctypes;435krb5_set_default_in_tkt_etypes(context, enctypes);436}437438/* canon name if needed for client + target realm */439kret = krb5_cc_get_config(context, ctx->ccache, NULL,440"realm-config", &outbuf);441if (kret == 0) {442/* XXX 2 is no server canon */443if (outbuf.length < 1 || ((((unsigned char *)outbuf.data)[0]) & 2))444allow_dns = 0;445krb5_data_free(&outbuf);446}447448/*449* First we try w/o dns, hope that the KDC have register alias450* (and referrals if cross realm) for this principal. If that451* fails and if we are allowed to using this realm try again with452* DNS canonicalizion.453*/454ret = gsskrb5_get_creds(minor_status, context, ctx->ccache,455ctx, name, 0, time_req,456time_rec);457if (ret && allow_dns)458ret = gsskrb5_get_creds(minor_status, context, ctx->ccache,459ctx, name, 1, time_req,460time_rec);461if (ret)462goto failure;463464ctx->lifetime = ctx->kcred->times.endtime;465466ret = _gss_DES3_get_mic_compat(minor_status, ctx, context);467if (ret)468goto failure;469470ret = _gsskrb5_lifetime_left(minor_status,471context,472ctx->lifetime,473&lifetime_rec);474if (ret)475goto failure;476477if (lifetime_rec == 0) {478*minor_status = 0;479ret = GSS_S_CONTEXT_EXPIRED;480goto failure;481}482483krb5_auth_con_setkey(context,484ctx->auth_context,485&ctx->kcred->session);486487kret = krb5_auth_con_generatelocalsubkey(context,488ctx->auth_context,489&ctx->kcred->session);490if(kret) {491*minor_status = kret;492ret = GSS_S_FAILURE;493goto failure;494}495496return GSS_S_COMPLETE;497498failure:499if (ctx->ccache && (ctx->more_flags & CLOSE_CCACHE))500krb5_cc_close(context, ctx->ccache);501ctx->ccache = NULL;502503return ret;504505}506507static OM_uint32508init_auth_restart509(OM_uint32 * minor_status,510gsskrb5_cred cred,511gsskrb5_ctx ctx,512krb5_context context,513OM_uint32 req_flags,514const gss_channel_bindings_t input_chan_bindings,515const gss_buffer_t input_token,516gss_OID * actual_mech_type,517gss_buffer_t output_token,518OM_uint32 * ret_flags,519OM_uint32 * time_rec520)521{522OM_uint32 ret = GSS_S_FAILURE;523krb5_error_code kret;524krb5_flags ap_options;525krb5_data outbuf;526uint32_t flags;527krb5_data authenticator;528Checksum cksum;529krb5_enctype enctype;530krb5_data fwd_data, timedata;531int32_t offset = 0, oldoffset = 0;532uint32_t flagmask;533534krb5_data_zero(&outbuf);535krb5_data_zero(&fwd_data);536537*minor_status = 0;538539/*540* If the credential doesn't have ok-as-delegate, check if there541* is a realm setting and use that.542*/543if (!ctx->kcred->flags.b.ok_as_delegate) {544krb5_data data;545546ret = krb5_cc_get_config(context, ctx->ccache, NULL,547"realm-config", &data);548if (ret == 0) {549/* XXX 1 is use ok-as-delegate */550if (data.length < 1 || ((((unsigned char *)data.data)[0]) & 1) == 0)551req_flags &= ~(GSS_C_DELEG_FLAG|GSS_C_DELEG_POLICY_FLAG);552krb5_data_free(&data);553}554}555556flagmask = 0;557558/* if we used GSS_C_DELEG_POLICY_FLAG, trust KDC */559if ((req_flags & GSS_C_DELEG_POLICY_FLAG)560&& ctx->kcred->flags.b.ok_as_delegate)561flagmask |= GSS_C_DELEG_FLAG | GSS_C_DELEG_POLICY_FLAG;562/* if there still is a GSS_C_DELEG_FLAG, use that */563if (req_flags & GSS_C_DELEG_FLAG)564flagmask |= GSS_C_DELEG_FLAG;565566567flags = 0;568ap_options = 0;569if (flagmask & GSS_C_DELEG_FLAG) {570do_delegation (context,571ctx->deleg_auth_context,572ctx->ccache, ctx->kcred, ctx->target,573&fwd_data, flagmask, &flags);574}575576if (req_flags & GSS_C_MUTUAL_FLAG) {577flags |= GSS_C_MUTUAL_FLAG;578ap_options |= AP_OPTS_MUTUAL_REQUIRED;579}580581if (req_flags & GSS_C_REPLAY_FLAG)582flags |= GSS_C_REPLAY_FLAG;583if (req_flags & GSS_C_SEQUENCE_FLAG)584flags |= GSS_C_SEQUENCE_FLAG;585#if 0586if (req_flags & GSS_C_ANON_FLAG)587; /* XXX */588#endif589if (req_flags & GSS_C_DCE_STYLE) {590/* GSS_C_DCE_STYLE implies GSS_C_MUTUAL_FLAG */591flags |= GSS_C_DCE_STYLE | GSS_C_MUTUAL_FLAG;592ap_options |= AP_OPTS_MUTUAL_REQUIRED;593}594if (req_flags & GSS_C_IDENTIFY_FLAG)595flags |= GSS_C_IDENTIFY_FLAG;596if (req_flags & GSS_C_EXTENDED_ERROR_FLAG)597flags |= GSS_C_EXTENDED_ERROR_FLAG;598599if (req_flags & GSS_C_CONF_FLAG) {600flags |= GSS_C_CONF_FLAG;601}602if (req_flags & GSS_C_INTEG_FLAG) {603flags |= GSS_C_INTEG_FLAG;604}605if (cred == NULL || !(cred->cred_flags & GSS_CF_NO_CI_FLAGS)) {606flags |= GSS_C_CONF_FLAG;607flags |= GSS_C_INTEG_FLAG;608}609flags |= GSS_C_TRANS_FLAG;610611if (ret_flags)612*ret_flags = flags;613ctx->flags = flags;614ctx->more_flags |= LOCAL;615616ret = _gsskrb5_create_8003_checksum (minor_status,617input_chan_bindings,618flags,619&fwd_data,620&cksum);621krb5_data_free (&fwd_data);622if (ret)623goto failure;624625enctype = ctx->auth_context->keyblock->keytype;626627ret = krb5_cc_get_config(context, ctx->ccache, ctx->target,628"time-offset", &timedata);629if (ret == 0) {630if (timedata.length == 4) {631const u_char *p = timedata.data;632offset = (p[0] <<24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);633}634krb5_data_free(&timedata);635}636637if (offset) {638krb5_get_kdc_sec_offset (context, &oldoffset, NULL);639krb5_set_kdc_sec_offset (context, offset, -1);640}641642kret = _krb5_build_authenticator(context,643ctx->auth_context,644enctype,645ctx->kcred,646&cksum,647&authenticator,648KRB5_KU_AP_REQ_AUTH);649650if (kret) {651if (offset)652krb5_set_kdc_sec_offset (context, oldoffset, -1);653*minor_status = kret;654ret = GSS_S_FAILURE;655goto failure;656}657658kret = krb5_build_ap_req (context,659enctype,660ctx->kcred,661ap_options,662authenticator,663&outbuf);664if (offset)665krb5_set_kdc_sec_offset (context, oldoffset, -1);666if (kret) {667*minor_status = kret;668ret = GSS_S_FAILURE;669goto failure;670}671672if (flags & GSS_C_DCE_STYLE) {673output_token->value = outbuf.data;674output_token->length = outbuf.length;675} else {676ret = _gsskrb5_encapsulate (minor_status, &outbuf, output_token,677(u_char *)(intptr_t)"\x01\x00",678GSS_KRB5_MECHANISM);679krb5_data_free (&outbuf);680if (ret)681goto failure;682}683684free_Checksum(&cksum);685686if (flags & GSS_C_MUTUAL_FLAG) {687ctx->state = INITIATOR_WAIT_FOR_MUTAL;688return GSS_S_CONTINUE_NEEDED;689}690691return gsskrb5_initiator_ready(minor_status, ctx, context);692failure:693if (ctx->ccache && (ctx->more_flags & CLOSE_CCACHE))694krb5_cc_close(context, ctx->ccache);695ctx->ccache = NULL;696697return ret;698}699700static krb5_error_code701handle_error_packet(krb5_context context,702gsskrb5_ctx ctx,703krb5_data indata)704{705krb5_error_code kret;706KRB_ERROR error;707708kret = krb5_rd_error(context, &indata, &error);709if (kret == 0) {710kret = krb5_error_from_rd_error(context, &error, NULL);711712/* save the time skrew for this host */713if (kret == KRB5KRB_AP_ERR_SKEW) {714krb5_data timedata;715unsigned char p[4];716int32_t t = error.stime - time(NULL);717718p[0] = (t >> 24) & 0xFF;719p[1] = (t >> 16) & 0xFF;720p[2] = (t >> 8) & 0xFF;721p[3] = (t >> 0) & 0xFF;722723timedata.data = p;724timedata.length = sizeof(p);725726krb5_cc_set_config(context, ctx->ccache, ctx->target,727"time-offset", &timedata);728729if ((ctx->more_flags & RETRIED) == 0)730ctx->state = INITIATOR_RESTART;731ctx->more_flags |= RETRIED;732}733free_KRB_ERROR (&error);734}735return kret;736}737738739static OM_uint32740repl_mutual741(OM_uint32 * minor_status,742gsskrb5_ctx ctx,743krb5_context context,744const gss_OID mech_type,745OM_uint32 req_flags,746OM_uint32 time_req,747const gss_channel_bindings_t input_chan_bindings,748const gss_buffer_t input_token,749gss_OID * actual_mech_type,750gss_buffer_t output_token,751OM_uint32 * ret_flags,752OM_uint32 * time_rec753)754{755OM_uint32 ret;756krb5_error_code kret;757krb5_data indata;758krb5_ap_rep_enc_part *repl;759760output_token->length = 0;761output_token->value = NULL;762763if (actual_mech_type)764*actual_mech_type = GSS_KRB5_MECHANISM;765766if (IS_DCE_STYLE(ctx)) {767/* There is no OID wrapping. */768indata.length = input_token->length;769indata.data = input_token->value;770kret = krb5_rd_rep(context,771ctx->auth_context,772&indata,773&repl);774if (kret) {775ret = _gsskrb5_decapsulate(minor_status,776input_token,777&indata,778"\x03\x00",779GSS_KRB5_MECHANISM);780if (ret == GSS_S_COMPLETE) {781*minor_status = handle_error_packet(context, ctx, indata);782} else {783*minor_status = kret;784}785return GSS_S_FAILURE;786}787} else {788ret = _gsskrb5_decapsulate (minor_status,789input_token,790&indata,791"\x02\x00",792GSS_KRB5_MECHANISM);793if (ret == GSS_S_DEFECTIVE_TOKEN) {794/* check if there is an error token sent instead */795ret = _gsskrb5_decapsulate (minor_status,796input_token,797&indata,798"\x03\x00",799GSS_KRB5_MECHANISM);800if (ret == GSS_S_COMPLETE) {801*minor_status = handle_error_packet(context, ctx, indata);802return GSS_S_FAILURE;803}804}805kret = krb5_rd_rep (context,806ctx->auth_context,807&indata,808&repl);809if (kret) {810*minor_status = kret;811return GSS_S_FAILURE;812}813}814815krb5_free_ap_rep_enc_part (context,816repl);817818*minor_status = 0;819if (time_rec) {820ret = _gsskrb5_lifetime_left(minor_status,821context,822ctx->lifetime,823time_rec);824} else {825ret = GSS_S_COMPLETE;826}827if (ret_flags)828*ret_flags = ctx->flags;829830if (req_flags & GSS_C_DCE_STYLE) {831int32_t local_seq, remote_seq;832krb5_data outbuf;833834/*835* So DCE_STYLE is strange. The client echos the seq number836* that the server used in the server's mk_rep in its own837* mk_rep(). After when done, it resets to it's own seq number838* for the gss_wrap calls.839*/840841krb5_auth_con_getremoteseqnumber(context, ctx->auth_context, &remote_seq);842krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, &local_seq);843krb5_auth_con_setlocalseqnumber(context, ctx->auth_context, remote_seq);844845kret = krb5_mk_rep(context, ctx->auth_context, &outbuf);846if (kret) {847*minor_status = kret;848return GSS_S_FAILURE;849}850851/* reset local seq number */852krb5_auth_con_setlocalseqnumber(context, ctx->auth_context, local_seq);853854output_token->length = outbuf.length;855output_token->value = outbuf.data;856}857858return gsskrb5_initiator_ready(minor_status, ctx, context);859}860861/*862* gss_init_sec_context863*/864865OM_uint32 GSSAPI_CALLCONV _gsskrb5_init_sec_context866(OM_uint32 * minor_status,867const gss_cred_id_t cred_handle,868gss_ctx_id_t * context_handle,869const gss_name_t target_name,870const gss_OID mech_type,871OM_uint32 req_flags,872OM_uint32 time_req,873const gss_channel_bindings_t input_chan_bindings,874const gss_buffer_t input_token,875gss_OID * actual_mech_type,876gss_buffer_t output_token,877OM_uint32 * ret_flags,878OM_uint32 * time_rec879)880{881krb5_context context;882gsskrb5_cred cred = (gsskrb5_cred)cred_handle;883gsskrb5_ctx ctx;884OM_uint32 ret;885886GSSAPI_KRB5_INIT (&context);887888output_token->length = 0;889output_token->value = NULL;890891if (context_handle == NULL) {892*minor_status = 0;893return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;894}895896if (ret_flags)897*ret_flags = 0;898if (time_rec)899*time_rec = 0;900901if (target_name == GSS_C_NO_NAME) {902if (actual_mech_type)903*actual_mech_type = GSS_C_NO_OID;904*minor_status = 0;905return GSS_S_BAD_NAME;906}907908if (mech_type != GSS_C_NO_OID &&909!gss_oid_equal(mech_type, GSS_KRB5_MECHANISM))910return GSS_S_BAD_MECH;911912if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) {913OM_uint32 ret1;914915if (*context_handle != GSS_C_NO_CONTEXT) {916*minor_status = 0;917return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;918}919920ret1 = _gsskrb5_create_ctx(minor_status,921context_handle,922context,923input_chan_bindings,924INITIATOR_START);925if (ret1)926return ret1;927}928929if (*context_handle == GSS_C_NO_CONTEXT) {930*minor_status = 0;931return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;932}933934ctx = (gsskrb5_ctx) *context_handle;935936HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);937938again:939switch (ctx->state) {940case INITIATOR_START:941ret = init_auth(minor_status,942cred,943ctx,944context,945target_name,946mech_type,947req_flags,948time_req,949input_token,950actual_mech_type,951output_token,952ret_flags,953time_rec);954if (ret != GSS_S_COMPLETE)955break;956/* FALL THOUGH */957case INITIATOR_RESTART:958ret = init_auth_restart(minor_status,959cred,960ctx,961context,962req_flags,963input_chan_bindings,964input_token,965actual_mech_type,966output_token,967ret_flags,968time_rec);969break;970case INITIATOR_WAIT_FOR_MUTAL:971ret = repl_mutual(minor_status,972ctx,973context,974mech_type,975req_flags,976time_req,977input_chan_bindings,978input_token,979actual_mech_type,980output_token,981ret_flags,982time_rec);983if (ctx->state == INITIATOR_RESTART)984goto again;985break;986case INITIATOR_READY:987/*988* If we get there, the caller have called989* gss_init_sec_context() one time too many.990*/991_gsskrb5_set_status(EINVAL, "init_sec_context "992"called one time too many");993*minor_status = EINVAL;994ret = GSS_S_BAD_STATUS;995break;996default:997_gsskrb5_set_status(EINVAL, "init_sec_context "998"invalid state %d for client",999(int)ctx->state);1000*minor_status = EINVAL;1001ret = GSS_S_BAD_STATUS;1002break;1003}1004HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);10051006/* destroy context in case of error */1007if (GSS_ERROR(ret)) {1008OM_uint32 min2;1009_gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER);1010}10111012return ret;10131014}101510161017