1178825Sdfr/* 2178825Sdfr * Copyright (c) 1997 - 2006 Kungliga Tekniska H�gskolan 3178825Sdfr * (Royal Institute of Technology, Stockholm, Sweden). 4178825Sdfr * All rights reserved. 5178825Sdfr * 6178825Sdfr * Redistribution and use in source and binary forms, with or without 7178825Sdfr * modification, are permitted provided that the following conditions 8178825Sdfr * are met: 9178825Sdfr * 10178825Sdfr * 1. Redistributions of source code must retain the above copyright 11178825Sdfr * notice, this list of conditions and the following disclaimer. 12178825Sdfr * 13178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright 14178825Sdfr * notice, this list of conditions and the following disclaimer in the 15178825Sdfr * documentation and/or other materials provided with the distribution. 16178825Sdfr * 17178825Sdfr * 3. Neither the name of the Institute nor the names of its contributors 18178825Sdfr * may be used to endorse or promote products derived from this software 19178825Sdfr * without specific prior written permission. 20178825Sdfr * 21178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24178825Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31178825Sdfr * SUCH DAMAGE. 32178825Sdfr */ 33178825Sdfr 34178825Sdfr#include "krb5/gsskrb5_locl.h" 35178825Sdfr 36178825SdfrRCSID("$Id: accept_sec_context.c 20199 2007-02-07 22:36:39Z lha $"); 37178825Sdfr 38178825SdfrHEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER; 39178825Sdfrkrb5_keytab _gsskrb5_keytab; 40178825Sdfr 41178825SdfrOM_uint32 42178825Sdfr_gsskrb5_register_acceptor_identity (const char *identity) 43178825Sdfr{ 44178825Sdfr krb5_context context; 45178825Sdfr krb5_error_code ret; 46178825Sdfr 47178825Sdfr ret = _gsskrb5_init(&context); 48178825Sdfr if(ret) 49178825Sdfr return GSS_S_FAILURE; 50178825Sdfr 51178825Sdfr HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex); 52178825Sdfr 53178825Sdfr if(_gsskrb5_keytab != NULL) { 54178825Sdfr krb5_kt_close(context, _gsskrb5_keytab); 55178825Sdfr _gsskrb5_keytab = NULL; 56178825Sdfr } 57178825Sdfr if (identity == NULL) { 58178825Sdfr ret = krb5_kt_default(context, &_gsskrb5_keytab); 59178825Sdfr } else { 60178825Sdfr char *p; 61178825Sdfr 62178825Sdfr asprintf(&p, "FILE:%s", identity); 63178825Sdfr if(p == NULL) { 64178825Sdfr HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); 65178825Sdfr return GSS_S_FAILURE; 66178825Sdfr } 67178825Sdfr ret = krb5_kt_resolve(context, p, &_gsskrb5_keytab); 68178825Sdfr free(p); 69178825Sdfr } 70178825Sdfr HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); 71178825Sdfr if(ret) 72178825Sdfr return GSS_S_FAILURE; 73178825Sdfr return GSS_S_COMPLETE; 74178825Sdfr} 75178825Sdfr 76178825Sdfrvoid 77178825Sdfr_gsskrb5i_is_cfx(gsskrb5_ctx ctx, int *is_cfx) 78178825Sdfr{ 79178825Sdfr krb5_keyblock *key; 80178825Sdfr int acceptor = (ctx->more_flags & LOCAL) == 0; 81178825Sdfr 82178825Sdfr *is_cfx = 0; 83178825Sdfr 84178825Sdfr if (acceptor) { 85178825Sdfr if (ctx->auth_context->local_subkey) 86178825Sdfr key = ctx->auth_context->local_subkey; 87178825Sdfr else 88178825Sdfr key = ctx->auth_context->remote_subkey; 89178825Sdfr } else { 90178825Sdfr if (ctx->auth_context->remote_subkey) 91178825Sdfr key = ctx->auth_context->remote_subkey; 92178825Sdfr else 93178825Sdfr key = ctx->auth_context->local_subkey; 94178825Sdfr } 95178825Sdfr if (key == NULL) 96178825Sdfr key = ctx->auth_context->keyblock; 97178825Sdfr 98178825Sdfr if (key == NULL) 99178825Sdfr return; 100178825Sdfr 101178825Sdfr switch (key->keytype) { 102178825Sdfr case ETYPE_DES_CBC_CRC: 103178825Sdfr case ETYPE_DES_CBC_MD4: 104178825Sdfr case ETYPE_DES_CBC_MD5: 105178825Sdfr case ETYPE_DES3_CBC_MD5: 106178825Sdfr case ETYPE_DES3_CBC_SHA1: 107178825Sdfr case ETYPE_ARCFOUR_HMAC_MD5: 108178825Sdfr case ETYPE_ARCFOUR_HMAC_MD5_56: 109178825Sdfr break; 110178825Sdfr default : 111178825Sdfr *is_cfx = 1; 112178825Sdfr if ((acceptor && ctx->auth_context->local_subkey) || 113178825Sdfr (!acceptor && ctx->auth_context->remote_subkey)) 114178825Sdfr ctx->more_flags |= ACCEPTOR_SUBKEY; 115178825Sdfr break; 116178825Sdfr } 117178825Sdfr} 118178825Sdfr 119178825Sdfr 120178825Sdfrstatic OM_uint32 121178825Sdfrgsskrb5_accept_delegated_token 122178825Sdfr(OM_uint32 * minor_status, 123178825Sdfr gsskrb5_ctx ctx, 124178825Sdfr krb5_context context, 125178825Sdfr gss_cred_id_t * delegated_cred_handle 126178825Sdfr ) 127178825Sdfr{ 128178825Sdfr krb5_ccache ccache = NULL; 129178825Sdfr krb5_error_code kret; 130178825Sdfr int32_t ac_flags, ret = GSS_S_COMPLETE; 131178825Sdfr 132178825Sdfr *minor_status = 0; 133178825Sdfr 134178825Sdfr /* XXX Create a new delegated_cred_handle? */ 135178825Sdfr if (delegated_cred_handle == NULL) { 136178825Sdfr kret = krb5_cc_default (context, &ccache); 137178825Sdfr } else { 138178825Sdfr *delegated_cred_handle = NULL; 139178825Sdfr kret = krb5_cc_gen_new (context, &krb5_mcc_ops, &ccache); 140178825Sdfr } 141178825Sdfr if (kret) { 142178825Sdfr ctx->flags &= ~GSS_C_DELEG_FLAG; 143178825Sdfr goto out; 144178825Sdfr } 145178825Sdfr 146178825Sdfr kret = krb5_cc_initialize(context, ccache, ctx->source); 147178825Sdfr if (kret) { 148178825Sdfr ctx->flags &= ~GSS_C_DELEG_FLAG; 149178825Sdfr goto out; 150178825Sdfr } 151178825Sdfr 152178825Sdfr krb5_auth_con_removeflags(context, 153178825Sdfr ctx->auth_context, 154178825Sdfr KRB5_AUTH_CONTEXT_DO_TIME, 155178825Sdfr &ac_flags); 156178825Sdfr kret = krb5_rd_cred2(context, 157178825Sdfr ctx->auth_context, 158178825Sdfr ccache, 159178825Sdfr &ctx->fwd_data); 160178825Sdfr krb5_auth_con_setflags(context, 161178825Sdfr ctx->auth_context, 162178825Sdfr ac_flags); 163178825Sdfr if (kret) { 164178825Sdfr ctx->flags &= ~GSS_C_DELEG_FLAG; 165178825Sdfr ret = GSS_S_FAILURE; 166178825Sdfr *minor_status = kret; 167178825Sdfr goto out; 168178825Sdfr } 169178825Sdfr 170178825Sdfr if (delegated_cred_handle) { 171178825Sdfr gsskrb5_cred handle; 172178825Sdfr 173178825Sdfr ret = _gsskrb5_import_cred(minor_status, 174178825Sdfr ccache, 175178825Sdfr NULL, 176178825Sdfr NULL, 177178825Sdfr delegated_cred_handle); 178178825Sdfr if (ret != GSS_S_COMPLETE) 179178825Sdfr goto out; 180178825Sdfr 181178825Sdfr handle = (gsskrb5_cred) *delegated_cred_handle; 182178825Sdfr 183178825Sdfr handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; 184178825Sdfr krb5_cc_close(context, ccache); 185178825Sdfr ccache = NULL; 186178825Sdfr } 187178825Sdfr 188178825Sdfrout: 189178825Sdfr if (ccache) { 190178825Sdfr /* Don't destroy the default cred cache */ 191178825Sdfr if (delegated_cred_handle == NULL) 192178825Sdfr krb5_cc_close(context, ccache); 193178825Sdfr else 194178825Sdfr krb5_cc_destroy(context, ccache); 195178825Sdfr } 196178825Sdfr return ret; 197178825Sdfr} 198178825Sdfr 199178825Sdfrstatic OM_uint32 200178825Sdfrgsskrb5_acceptor_ready(OM_uint32 * minor_status, 201178825Sdfr gsskrb5_ctx ctx, 202178825Sdfr krb5_context context, 203178825Sdfr gss_cred_id_t *delegated_cred_handle) 204178825Sdfr{ 205178825Sdfr OM_uint32 ret; 206178825Sdfr int32_t seq_number; 207178825Sdfr int is_cfx = 0; 208178825Sdfr 209178825Sdfr krb5_auth_getremoteseqnumber (context, 210178825Sdfr ctx->auth_context, 211178825Sdfr &seq_number); 212178825Sdfr 213178825Sdfr _gsskrb5i_is_cfx(ctx, &is_cfx); 214178825Sdfr 215178825Sdfr ret = _gssapi_msg_order_create(minor_status, 216178825Sdfr &ctx->order, 217178825Sdfr _gssapi_msg_order_f(ctx->flags), 218178825Sdfr seq_number, 0, is_cfx); 219178825Sdfr if (ret) 220178825Sdfr return ret; 221178825Sdfr 222178825Sdfr /* 223178825Sdfr * If requested, set local sequence num to remote sequence if this 224178825Sdfr * isn't a mutual authentication context 225178825Sdfr */ 226178825Sdfr if (!(ctx->flags & GSS_C_MUTUAL_FLAG) && _gssapi_msg_order_f(ctx->flags)) { 227178825Sdfr krb5_auth_con_setlocalseqnumber(context, 228178825Sdfr ctx->auth_context, 229178825Sdfr seq_number); 230178825Sdfr } 231178825Sdfr 232178825Sdfr /* 233178825Sdfr * We should handle the delegation ticket, in case it's there 234178825Sdfr */ 235178825Sdfr if (ctx->fwd_data.length > 0 && (ctx->flags & GSS_C_DELEG_FLAG)) { 236178825Sdfr ret = gsskrb5_accept_delegated_token(minor_status, 237178825Sdfr ctx, 238178825Sdfr context, 239178825Sdfr delegated_cred_handle); 240178825Sdfr if (ret) 241178825Sdfr return ret; 242178825Sdfr } else { 243178825Sdfr /* Well, looks like it wasn't there after all */ 244178825Sdfr ctx->flags &= ~GSS_C_DELEG_FLAG; 245178825Sdfr } 246178825Sdfr 247178825Sdfr ctx->state = ACCEPTOR_READY; 248178825Sdfr ctx->more_flags |= OPEN; 249178825Sdfr 250178825Sdfr return GSS_S_COMPLETE; 251178825Sdfr} 252178825Sdfr 253178825Sdfrstatic OM_uint32 254178825Sdfrgsskrb5_acceptor_start(OM_uint32 * minor_status, 255178825Sdfr gsskrb5_ctx ctx, 256178825Sdfr krb5_context context, 257178825Sdfr const gss_cred_id_t acceptor_cred_handle, 258178825Sdfr const gss_buffer_t input_token_buffer, 259178825Sdfr const gss_channel_bindings_t input_chan_bindings, 260178825Sdfr gss_name_t * src_name, 261178825Sdfr gss_OID * mech_type, 262178825Sdfr gss_buffer_t output_token, 263178825Sdfr OM_uint32 * ret_flags, 264178825Sdfr OM_uint32 * time_rec, 265178825Sdfr gss_cred_id_t * delegated_cred_handle) 266178825Sdfr{ 267178825Sdfr krb5_error_code kret; 268178825Sdfr OM_uint32 ret = GSS_S_COMPLETE; 269178825Sdfr krb5_data indata; 270178825Sdfr krb5_flags ap_options; 271178825Sdfr krb5_keytab keytab = NULL; 272178825Sdfr int is_cfx = 0; 273178825Sdfr const gsskrb5_cred acceptor_cred = (gsskrb5_cred)acceptor_cred_handle; 274178825Sdfr 275178825Sdfr /* 276178825Sdfr * We may, or may not, have an escapsulation. 277178825Sdfr */ 278178825Sdfr ret = _gsskrb5_decapsulate (minor_status, 279178825Sdfr input_token_buffer, 280178825Sdfr &indata, 281178825Sdfr "\x01\x00", 282178825Sdfr GSS_KRB5_MECHANISM); 283178825Sdfr 284178825Sdfr if (ret) { 285178825Sdfr /* Assume that there is no OID wrapping. */ 286178825Sdfr indata.length = input_token_buffer->length; 287178825Sdfr indata.data = input_token_buffer->value; 288178825Sdfr } 289178825Sdfr 290178825Sdfr /* 291178825Sdfr * We need to get our keytab 292178825Sdfr */ 293178825Sdfr if (acceptor_cred == NULL) { 294178825Sdfr if (_gsskrb5_keytab != NULL) 295178825Sdfr keytab = _gsskrb5_keytab; 296178825Sdfr } else if (acceptor_cred->keytab != NULL) { 297178825Sdfr keytab = acceptor_cred->keytab; 298178825Sdfr } 299178825Sdfr 300178825Sdfr /* 301178825Sdfr * We need to check the ticket and create the AP-REP packet 302178825Sdfr */ 303178825Sdfr 304178825Sdfr { 305178825Sdfr krb5_rd_req_in_ctx in = NULL; 306178825Sdfr krb5_rd_req_out_ctx out = NULL; 307178825Sdfr 308178825Sdfr kret = krb5_rd_req_in_ctx_alloc(context, &in); 309178825Sdfr if (kret == 0) 310178825Sdfr kret = krb5_rd_req_in_set_keytab(context, in, keytab); 311178825Sdfr if (kret) { 312178825Sdfr if (in) 313178825Sdfr krb5_rd_req_in_ctx_free(context, in); 314178825Sdfr ret = GSS_S_FAILURE; 315178825Sdfr *minor_status = kret; 316178825Sdfr return ret; 317178825Sdfr } 318178825Sdfr 319178825Sdfr kret = krb5_rd_req_ctx(context, 320178825Sdfr &ctx->auth_context, 321178825Sdfr &indata, 322178825Sdfr (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) ? NULL : acceptor_cred->principal, 323178825Sdfr in, &out); 324178825Sdfr krb5_rd_req_in_ctx_free(context, in); 325178825Sdfr if (kret) { 326178825Sdfr ret = GSS_S_FAILURE; 327178825Sdfr *minor_status = kret; 328178825Sdfr return ret; 329178825Sdfr } 330178825Sdfr 331178825Sdfr /* 332178825Sdfr * We need to remember some data on the context_handle. 333178825Sdfr */ 334178825Sdfr kret = krb5_rd_req_out_get_ap_req_options(context, out, 335178825Sdfr &ap_options); 336178825Sdfr if (kret == 0) 337178825Sdfr kret = krb5_rd_req_out_get_ticket(context, out, 338178825Sdfr &ctx->ticket); 339178825Sdfr if (kret == 0) 340178825Sdfr kret = krb5_rd_req_out_get_keyblock(context, out, 341178825Sdfr &ctx->service_keyblock); 342178825Sdfr ctx->lifetime = ctx->ticket->ticket.endtime; 343178825Sdfr 344178825Sdfr krb5_rd_req_out_ctx_free(context, out); 345178825Sdfr if (kret) { 346178825Sdfr ret = GSS_S_FAILURE; 347178825Sdfr *minor_status = kret; 348178825Sdfr return ret; 349178825Sdfr } 350178825Sdfr } 351178825Sdfr 352178825Sdfr 353178825Sdfr /* 354178825Sdfr * We need to copy the principal names to the context and the 355178825Sdfr * calling layer. 356178825Sdfr */ 357178825Sdfr kret = krb5_copy_principal(context, 358178825Sdfr ctx->ticket->client, 359178825Sdfr &ctx->source); 360178825Sdfr if (kret) { 361178825Sdfr ret = GSS_S_FAILURE; 362178825Sdfr *minor_status = kret; 363178825Sdfr } 364178825Sdfr 365178825Sdfr kret = krb5_copy_principal(context, 366178825Sdfr ctx->ticket->server, 367178825Sdfr &ctx->target); 368178825Sdfr if (kret) { 369178825Sdfr ret = GSS_S_FAILURE; 370178825Sdfr *minor_status = kret; 371178825Sdfr return ret; 372178825Sdfr } 373178825Sdfr 374178825Sdfr /* 375178825Sdfr * We need to setup some compat stuff, this assumes that 376178825Sdfr * context_handle->target is already set. 377178825Sdfr */ 378178825Sdfr ret = _gss_DES3_get_mic_compat(minor_status, ctx, context); 379178825Sdfr if (ret) 380178825Sdfr return ret; 381178825Sdfr 382178825Sdfr if (src_name != NULL) { 383178825Sdfr kret = krb5_copy_principal (context, 384178825Sdfr ctx->ticket->client, 385178825Sdfr (gsskrb5_name*)src_name); 386178825Sdfr if (kret) { 387178825Sdfr ret = GSS_S_FAILURE; 388178825Sdfr *minor_status = kret; 389178825Sdfr return ret; 390178825Sdfr } 391178825Sdfr } 392178825Sdfr 393178825Sdfr /* 394178825Sdfr * We need to get the flags out of the 8003 checksum. 395178825Sdfr */ 396178825Sdfr { 397178825Sdfr krb5_authenticator authenticator; 398178825Sdfr 399178825Sdfr kret = krb5_auth_con_getauthenticator(context, 400178825Sdfr ctx->auth_context, 401178825Sdfr &authenticator); 402178825Sdfr if(kret) { 403178825Sdfr ret = GSS_S_FAILURE; 404178825Sdfr *minor_status = kret; 405178825Sdfr return ret; 406178825Sdfr } 407178825Sdfr 408178825Sdfr if (authenticator->cksum->cksumtype == CKSUMTYPE_GSSAPI) { 409178825Sdfr ret = _gsskrb5_verify_8003_checksum(minor_status, 410178825Sdfr input_chan_bindings, 411178825Sdfr authenticator->cksum, 412178825Sdfr &ctx->flags, 413178825Sdfr &ctx->fwd_data); 414178825Sdfr 415178825Sdfr krb5_free_authenticator(context, &authenticator); 416178825Sdfr if (ret) { 417178825Sdfr return ret; 418178825Sdfr } 419178825Sdfr } else { 420178825Sdfr krb5_crypto crypto; 421178825Sdfr 422178825Sdfr kret = krb5_crypto_init(context, 423178825Sdfr ctx->auth_context->keyblock, 424178825Sdfr 0, &crypto); 425178825Sdfr if(kret) { 426178825Sdfr krb5_free_authenticator(context, &authenticator); 427178825Sdfr 428178825Sdfr ret = GSS_S_FAILURE; 429178825Sdfr *minor_status = kret; 430178825Sdfr return ret; 431178825Sdfr } 432178825Sdfr 433178825Sdfr /* 434178825Sdfr * Windows accepts Samba3's use of a kerberos, rather than 435178825Sdfr * GSSAPI checksum here 436178825Sdfr */ 437178825Sdfr 438178825Sdfr kret = krb5_verify_checksum(context, 439178825Sdfr crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0, 440178825Sdfr authenticator->cksum); 441178825Sdfr krb5_free_authenticator(context, &authenticator); 442178825Sdfr krb5_crypto_destroy(context, crypto); 443178825Sdfr 444178825Sdfr if(kret) { 445178825Sdfr ret = GSS_S_BAD_SIG; 446178825Sdfr *minor_status = kret; 447178825Sdfr return ret; 448178825Sdfr } 449178825Sdfr 450178825Sdfr /* 451178825Sdfr * Samba style get some flags (but not DCE-STYLE) 452178825Sdfr */ 453178825Sdfr ctx->flags = 454178825Sdfr GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG; 455178825Sdfr } 456178825Sdfr } 457178825Sdfr 458178825Sdfr if(ctx->flags & GSS_C_MUTUAL_FLAG) { 459178825Sdfr krb5_data outbuf; 460178825Sdfr 461178825Sdfr _gsskrb5i_is_cfx(ctx, &is_cfx); 462178825Sdfr 463178825Sdfr if (is_cfx != 0 464178825Sdfr || (ap_options & AP_OPTS_USE_SUBKEY)) { 465178825Sdfr kret = krb5_auth_con_addflags(context, 466178825Sdfr ctx->auth_context, 467178825Sdfr KRB5_AUTH_CONTEXT_USE_SUBKEY, 468178825Sdfr NULL); 469178825Sdfr ctx->more_flags |= ACCEPTOR_SUBKEY; 470178825Sdfr } 471178825Sdfr 472178825Sdfr kret = krb5_mk_rep(context, 473178825Sdfr ctx->auth_context, 474178825Sdfr &outbuf); 475178825Sdfr if (kret) { 476178825Sdfr *minor_status = kret; 477178825Sdfr return GSS_S_FAILURE; 478178825Sdfr } 479178825Sdfr 480178825Sdfr if (IS_DCE_STYLE(ctx)) { 481178825Sdfr output_token->length = outbuf.length; 482178825Sdfr output_token->value = outbuf.data; 483178825Sdfr } else { 484178825Sdfr ret = _gsskrb5_encapsulate(minor_status, 485178825Sdfr &outbuf, 486178825Sdfr output_token, 487178825Sdfr "\x02\x00", 488178825Sdfr GSS_KRB5_MECHANISM); 489178825Sdfr krb5_data_free (&outbuf); 490178825Sdfr if (ret) 491178825Sdfr return ret; 492178825Sdfr } 493178825Sdfr } 494178825Sdfr 495178825Sdfr ctx->flags |= GSS_C_TRANS_FLAG; 496178825Sdfr 497178825Sdfr /* Remember the flags */ 498178825Sdfr 499178825Sdfr ctx->lifetime = ctx->ticket->ticket.endtime; 500178825Sdfr ctx->more_flags |= OPEN; 501178825Sdfr 502178825Sdfr if (mech_type) 503178825Sdfr *mech_type = GSS_KRB5_MECHANISM; 504178825Sdfr 505178825Sdfr if (time_rec) { 506178825Sdfr ret = _gsskrb5_lifetime_left(minor_status, 507178825Sdfr context, 508178825Sdfr ctx->lifetime, 509178825Sdfr time_rec); 510178825Sdfr if (ret) { 511178825Sdfr return ret; 512178825Sdfr } 513178825Sdfr } 514178825Sdfr 515178825Sdfr /* 516178825Sdfr * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from 517178825Sdfr * the client. 518178825Sdfr */ 519178825Sdfr if (IS_DCE_STYLE(ctx)) { 520178825Sdfr /* 521178825Sdfr * Return flags to caller, but we haven't processed 522178825Sdfr * delgations yet 523178825Sdfr */ 524178825Sdfr if (ret_flags) 525178825Sdfr *ret_flags = (ctx->flags & ~GSS_C_DELEG_FLAG); 526178825Sdfr 527178825Sdfr ctx->state = ACCEPTOR_WAIT_FOR_DCESTYLE; 528178825Sdfr return GSS_S_CONTINUE_NEEDED; 529178825Sdfr } 530178825Sdfr 531178825Sdfr ret = gsskrb5_acceptor_ready(minor_status, ctx, context, 532178825Sdfr delegated_cred_handle); 533178825Sdfr 534178825Sdfr if (ret_flags) 535178825Sdfr *ret_flags = ctx->flags; 536178825Sdfr 537178825Sdfr return ret; 538178825Sdfr} 539178825Sdfr 540178825Sdfrstatic OM_uint32 541178825Sdfracceptor_wait_for_dcestyle(OM_uint32 * minor_status, 542178825Sdfr gsskrb5_ctx ctx, 543178825Sdfr krb5_context context, 544178825Sdfr const gss_cred_id_t acceptor_cred_handle, 545178825Sdfr const gss_buffer_t input_token_buffer, 546178825Sdfr const gss_channel_bindings_t input_chan_bindings, 547178825Sdfr gss_name_t * src_name, 548178825Sdfr gss_OID * mech_type, 549178825Sdfr gss_buffer_t output_token, 550178825Sdfr OM_uint32 * ret_flags, 551178825Sdfr OM_uint32 * time_rec, 552178825Sdfr gss_cred_id_t * delegated_cred_handle) 553178825Sdfr{ 554178825Sdfr OM_uint32 ret; 555178825Sdfr krb5_error_code kret; 556178825Sdfr krb5_data inbuf; 557178825Sdfr int32_t r_seq_number, l_seq_number; 558178825Sdfr 559178825Sdfr /* 560178825Sdfr * We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP 561178825Sdfr */ 562178825Sdfr 563178825Sdfr inbuf.length = input_token_buffer->length; 564178825Sdfr inbuf.data = input_token_buffer->value; 565178825Sdfr 566178825Sdfr /* 567178825Sdfr * We need to remeber the old remote seq_number, then check if the 568178825Sdfr * client has replied with our local seq_number, and then reset 569178825Sdfr * the remote seq_number to the old value 570178825Sdfr */ 571178825Sdfr { 572178825Sdfr kret = krb5_auth_con_getlocalseqnumber(context, 573178825Sdfr ctx->auth_context, 574178825Sdfr &l_seq_number); 575178825Sdfr if (kret) { 576178825Sdfr *minor_status = kret; 577178825Sdfr return GSS_S_FAILURE; 578178825Sdfr } 579178825Sdfr 580178825Sdfr kret = krb5_auth_getremoteseqnumber(context, 581178825Sdfr ctx->auth_context, 582178825Sdfr &r_seq_number); 583178825Sdfr if (kret) { 584178825Sdfr *minor_status = kret; 585178825Sdfr return GSS_S_FAILURE; 586178825Sdfr } 587178825Sdfr 588178825Sdfr kret = krb5_auth_con_setremoteseqnumber(context, 589178825Sdfr ctx->auth_context, 590178825Sdfr l_seq_number); 591178825Sdfr if (kret) { 592178825Sdfr *minor_status = kret; 593178825Sdfr return GSS_S_FAILURE; 594178825Sdfr } 595178825Sdfr } 596178825Sdfr 597178825Sdfr /* 598178825Sdfr * We need to verify the AP_REP, but we need to flag that this is 599178825Sdfr * DCE_STYLE, so don't check the timestamps this time, but put the 600178825Sdfr * flag DO_TIME back afterward. 601178825Sdfr */ 602178825Sdfr { 603178825Sdfr krb5_ap_rep_enc_part *repl; 604178825Sdfr int32_t auth_flags; 605178825Sdfr 606178825Sdfr krb5_auth_con_removeflags(context, 607178825Sdfr ctx->auth_context, 608178825Sdfr KRB5_AUTH_CONTEXT_DO_TIME, 609178825Sdfr &auth_flags); 610178825Sdfr 611178825Sdfr kret = krb5_rd_rep(context, ctx->auth_context, &inbuf, &repl); 612178825Sdfr if (kret) { 613178825Sdfr *minor_status = kret; 614178825Sdfr return GSS_S_FAILURE; 615178825Sdfr } 616178825Sdfr krb5_free_ap_rep_enc_part(context, repl); 617178825Sdfr krb5_auth_con_setflags(context, ctx->auth_context, auth_flags); 618178825Sdfr } 619178825Sdfr 620178825Sdfr /* We need to check the liftime */ 621178825Sdfr { 622178825Sdfr OM_uint32 lifetime_rec; 623178825Sdfr 624178825Sdfr ret = _gsskrb5_lifetime_left(minor_status, 625178825Sdfr context, 626178825Sdfr ctx->lifetime, 627178825Sdfr &lifetime_rec); 628178825Sdfr if (ret) { 629178825Sdfr return ret; 630178825Sdfr } 631178825Sdfr if (lifetime_rec == 0) { 632178825Sdfr return GSS_S_CONTEXT_EXPIRED; 633178825Sdfr } 634178825Sdfr 635178825Sdfr if (time_rec) *time_rec = lifetime_rec; 636178825Sdfr } 637178825Sdfr 638178825Sdfr /* We need to give the caller the flags which are in use */ 639178825Sdfr if (ret_flags) *ret_flags = ctx->flags; 640178825Sdfr 641178825Sdfr if (src_name) { 642178825Sdfr kret = krb5_copy_principal(context, 643178825Sdfr ctx->source, 644178825Sdfr (gsskrb5_name*)src_name); 645178825Sdfr if (kret) { 646178825Sdfr *minor_status = kret; 647178825Sdfr return GSS_S_FAILURE; 648178825Sdfr } 649178825Sdfr } 650178825Sdfr 651178825Sdfr /* 652178825Sdfr * After the krb5_rd_rep() the remote and local seq_number should 653178825Sdfr * be the same, because the client just replies the seq_number 654178825Sdfr * from our AP-REP in its AP-REP, but then the client uses the 655178825Sdfr * seq_number from its AP-REQ for GSS_wrap() 656178825Sdfr */ 657178825Sdfr { 658178825Sdfr int32_t tmp_r_seq_number, tmp_l_seq_number; 659178825Sdfr 660178825Sdfr kret = krb5_auth_getremoteseqnumber(context, 661178825Sdfr ctx->auth_context, 662178825Sdfr &tmp_r_seq_number); 663178825Sdfr if (kret) { 664178825Sdfr *minor_status = kret; 665178825Sdfr return GSS_S_FAILURE; 666178825Sdfr } 667178825Sdfr 668178825Sdfr kret = krb5_auth_con_getlocalseqnumber(context, 669178825Sdfr ctx->auth_context, 670178825Sdfr &tmp_l_seq_number); 671178825Sdfr if (kret) { 672178825Sdfr 673178825Sdfr *minor_status = kret; 674178825Sdfr return GSS_S_FAILURE; 675178825Sdfr } 676178825Sdfr 677178825Sdfr /* 678178825Sdfr * Here we check if the client has responsed with our local seq_number, 679178825Sdfr */ 680178825Sdfr if (tmp_r_seq_number != tmp_l_seq_number) { 681178825Sdfr return GSS_S_UNSEQ_TOKEN; 682178825Sdfr } 683178825Sdfr } 684178825Sdfr 685178825Sdfr /* 686178825Sdfr * We need to reset the remote seq_number, because the client will use, 687178825Sdfr * the old one for the GSS_wrap() calls 688178825Sdfr */ 689178825Sdfr { 690178825Sdfr kret = krb5_auth_con_setremoteseqnumber(context, 691178825Sdfr ctx->auth_context, 692178825Sdfr r_seq_number); 693178825Sdfr if (kret) { 694178825Sdfr *minor_status = kret; 695178825Sdfr return GSS_S_FAILURE; 696178825Sdfr } 697178825Sdfr } 698178825Sdfr 699178825Sdfr return gsskrb5_acceptor_ready(minor_status, ctx, context, 700178825Sdfr delegated_cred_handle); 701178825Sdfr} 702178825Sdfr 703178825Sdfr 704178825SdfrOM_uint32 705178825Sdfr_gsskrb5_accept_sec_context(OM_uint32 * minor_status, 706178825Sdfr gss_ctx_id_t * context_handle, 707178825Sdfr const gss_cred_id_t acceptor_cred_handle, 708178825Sdfr const gss_buffer_t input_token_buffer, 709178825Sdfr const gss_channel_bindings_t input_chan_bindings, 710178825Sdfr gss_name_t * src_name, 711178825Sdfr gss_OID * mech_type, 712178825Sdfr gss_buffer_t output_token, 713178825Sdfr OM_uint32 * ret_flags, 714178825Sdfr OM_uint32 * time_rec, 715178825Sdfr gss_cred_id_t * delegated_cred_handle) 716178825Sdfr{ 717178825Sdfr krb5_context context; 718178825Sdfr OM_uint32 ret; 719178825Sdfr gsskrb5_ctx ctx; 720178825Sdfr 721178825Sdfr GSSAPI_KRB5_INIT(&context); 722178825Sdfr 723178825Sdfr output_token->length = 0; 724178825Sdfr output_token->value = NULL; 725178825Sdfr 726178825Sdfr if (src_name != NULL) 727178825Sdfr *src_name = NULL; 728178825Sdfr if (mech_type) 729178825Sdfr *mech_type = GSS_KRB5_MECHANISM; 730178825Sdfr 731178825Sdfr if (*context_handle == GSS_C_NO_CONTEXT) { 732178825Sdfr ret = _gsskrb5_create_ctx(minor_status, 733178825Sdfr context_handle, 734178825Sdfr context, 735178825Sdfr input_chan_bindings, 736178825Sdfr ACCEPTOR_START); 737178825Sdfr if (ret) 738178825Sdfr return ret; 739178825Sdfr } 740178825Sdfr 741178825Sdfr ctx = (gsskrb5_ctx)*context_handle; 742178825Sdfr 743178825Sdfr 744178825Sdfr /* 745178825Sdfr * TODO: check the channel_bindings 746178825Sdfr * (above just sets them to krb5 layer) 747178825Sdfr */ 748178825Sdfr 749178825Sdfr HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 750178825Sdfr 751178825Sdfr switch (ctx->state) { 752178825Sdfr case ACCEPTOR_START: 753178825Sdfr ret = gsskrb5_acceptor_start(minor_status, 754178825Sdfr ctx, 755178825Sdfr context, 756178825Sdfr acceptor_cred_handle, 757178825Sdfr input_token_buffer, 758178825Sdfr input_chan_bindings, 759178825Sdfr src_name, 760178825Sdfr mech_type, 761178825Sdfr output_token, 762178825Sdfr ret_flags, 763178825Sdfr time_rec, 764178825Sdfr delegated_cred_handle); 765178825Sdfr break; 766178825Sdfr case ACCEPTOR_WAIT_FOR_DCESTYLE: 767178825Sdfr ret = acceptor_wait_for_dcestyle(minor_status, 768178825Sdfr ctx, 769178825Sdfr context, 770178825Sdfr acceptor_cred_handle, 771178825Sdfr input_token_buffer, 772178825Sdfr input_chan_bindings, 773178825Sdfr src_name, 774178825Sdfr mech_type, 775178825Sdfr output_token, 776178825Sdfr ret_flags, 777178825Sdfr time_rec, 778178825Sdfr delegated_cred_handle); 779178825Sdfr break; 780178825Sdfr case ACCEPTOR_READY: 781178825Sdfr /* 782178825Sdfr * If we get there, the caller have called 783178825Sdfr * gss_accept_sec_context() one time too many. 784178825Sdfr */ 785178825Sdfr ret = GSS_S_BAD_STATUS; 786178825Sdfr break; 787178825Sdfr default: 788178825Sdfr /* TODO: is this correct here? --metze */ 789178825Sdfr ret = GSS_S_BAD_STATUS; 790178825Sdfr break; 791178825Sdfr } 792178825Sdfr 793178825Sdfr HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 794178825Sdfr 795178825Sdfr if (GSS_ERROR(ret)) { 796178825Sdfr OM_uint32 min2; 797178825Sdfr _gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER); 798178825Sdfr } 799178825Sdfr 800178825Sdfr return ret; 801178825Sdfr} 802