1178825Sdfr/* 2233294Sstas * Copyright (c) 1997 - 2006 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 5178825Sdfr * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 9178825Sdfr * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 12178825Sdfr * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 16178825Sdfr * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 20178825Sdfr * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 32178825Sdfr */ 33178825Sdfr 34233294Sstas#include "gsskrb5_locl.h" 35178825Sdfr 36178825SdfrHEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER; 37178825Sdfrkrb5_keytab _gsskrb5_keytab; 38178825Sdfr 39233294Sstasstatic krb5_error_code 40233294Sstasvalidate_keytab(krb5_context context, const char *name, krb5_keytab *id) 41233294Sstas{ 42233294Sstas krb5_error_code ret; 43233294Sstas 44233294Sstas ret = krb5_kt_resolve(context, name, id); 45233294Sstas if (ret) 46233294Sstas return ret; 47233294Sstas 48233294Sstas ret = krb5_kt_have_content(context, *id); 49233294Sstas if (ret) { 50233294Sstas krb5_kt_close(context, *id); 51233294Sstas *id = NULL; 52233294Sstas } 53233294Sstas 54233294Sstas return ret; 55233294Sstas} 56233294Sstas 57178825SdfrOM_uint32 58233294Sstas_gsskrb5_register_acceptor_identity(OM_uint32 *min_stat, const char *identity) 59178825Sdfr{ 60178825Sdfr krb5_context context; 61178825Sdfr krb5_error_code ret; 62178825Sdfr 63233294Sstas *min_stat = 0; 64233294Sstas 65178825Sdfr ret = _gsskrb5_init(&context); 66178825Sdfr if(ret) 67178825Sdfr return GSS_S_FAILURE; 68233294Sstas 69178825Sdfr HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex); 70178825Sdfr 71178825Sdfr if(_gsskrb5_keytab != NULL) { 72178825Sdfr krb5_kt_close(context, _gsskrb5_keytab); 73178825Sdfr _gsskrb5_keytab = NULL; 74178825Sdfr } 75178825Sdfr if (identity == NULL) { 76178825Sdfr ret = krb5_kt_default(context, &_gsskrb5_keytab); 77178825Sdfr } else { 78233294Sstas /* 79233294Sstas * First check if we can the keytab as is and if it has content... 80233294Sstas */ 81233294Sstas ret = validate_keytab(context, identity, &_gsskrb5_keytab); 82233294Sstas /* 83233294Sstas * if it doesn't, lets prepend FILE: and try again 84233294Sstas */ 85233294Sstas if (ret) { 86233294Sstas char *p = NULL; 87233294Sstas ret = asprintf(&p, "FILE:%s", identity); 88233294Sstas if(ret < 0 || p == NULL) { 89233294Sstas HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); 90233294Sstas return GSS_S_FAILURE; 91233294Sstas } 92233294Sstas ret = validate_keytab(context, p, &_gsskrb5_keytab); 93233294Sstas free(p); 94178825Sdfr } 95178825Sdfr } 96178825Sdfr HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); 97233294Sstas if(ret) { 98233294Sstas *min_stat = ret; 99178825Sdfr return GSS_S_FAILURE; 100233294Sstas } 101178825Sdfr return GSS_S_COMPLETE; 102178825Sdfr} 103178825Sdfr 104178825Sdfrvoid 105233294Sstas_gsskrb5i_is_cfx(krb5_context context, gsskrb5_ctx ctx, int acceptor) 106178825Sdfr{ 107233294Sstas krb5_error_code ret; 108178825Sdfr krb5_keyblock *key; 109178825Sdfr 110178825Sdfr if (acceptor) { 111178825Sdfr if (ctx->auth_context->local_subkey) 112178825Sdfr key = ctx->auth_context->local_subkey; 113178825Sdfr else 114178825Sdfr key = ctx->auth_context->remote_subkey; 115178825Sdfr } else { 116178825Sdfr if (ctx->auth_context->remote_subkey) 117178825Sdfr key = ctx->auth_context->remote_subkey; 118178825Sdfr else 119178825Sdfr key = ctx->auth_context->local_subkey; 120178825Sdfr } 121178825Sdfr if (key == NULL) 122178825Sdfr key = ctx->auth_context->keyblock; 123178825Sdfr 124178825Sdfr if (key == NULL) 125178825Sdfr return; 126233294Sstas 127178825Sdfr switch (key->keytype) { 128178825Sdfr case ETYPE_DES_CBC_CRC: 129178825Sdfr case ETYPE_DES_CBC_MD4: 130178825Sdfr case ETYPE_DES_CBC_MD5: 131178825Sdfr case ETYPE_DES3_CBC_MD5: 132233294Sstas case ETYPE_OLD_DES3_CBC_SHA1: 133178825Sdfr case ETYPE_DES3_CBC_SHA1: 134178825Sdfr case ETYPE_ARCFOUR_HMAC_MD5: 135178825Sdfr case ETYPE_ARCFOUR_HMAC_MD5_56: 136178825Sdfr break; 137178825Sdfr default : 138233294Sstas ctx->more_flags |= IS_CFX; 139233294Sstas 140178825Sdfr if ((acceptor && ctx->auth_context->local_subkey) || 141178825Sdfr (!acceptor && ctx->auth_context->remote_subkey)) 142178825Sdfr ctx->more_flags |= ACCEPTOR_SUBKEY; 143178825Sdfr break; 144178825Sdfr } 145233294Sstas if (ctx->crypto) 146233294Sstas krb5_crypto_destroy(context, ctx->crypto); 147233294Sstas ret = krb5_crypto_init(context, key, 0, &ctx->crypto); 148178825Sdfr} 149178825Sdfr 150178825Sdfr 151178825Sdfrstatic OM_uint32 152178825Sdfrgsskrb5_accept_delegated_token 153178825Sdfr(OM_uint32 * minor_status, 154178825Sdfr gsskrb5_ctx ctx, 155178825Sdfr krb5_context context, 156178825Sdfr gss_cred_id_t * delegated_cred_handle 157178825Sdfr ) 158178825Sdfr{ 159178825Sdfr krb5_ccache ccache = NULL; 160178825Sdfr krb5_error_code kret; 161178825Sdfr int32_t ac_flags, ret = GSS_S_COMPLETE; 162233294Sstas 163178825Sdfr *minor_status = 0; 164178825Sdfr 165178825Sdfr /* XXX Create a new delegated_cred_handle? */ 166178825Sdfr if (delegated_cred_handle == NULL) { 167178825Sdfr kret = krb5_cc_default (context, &ccache); 168178825Sdfr } else { 169178825Sdfr *delegated_cred_handle = NULL; 170233294Sstas kret = krb5_cc_new_unique (context, krb5_cc_type_memory, 171233294Sstas NULL, &ccache); 172178825Sdfr } 173178825Sdfr if (kret) { 174178825Sdfr ctx->flags &= ~GSS_C_DELEG_FLAG; 175178825Sdfr goto out; 176178825Sdfr } 177178825Sdfr 178178825Sdfr kret = krb5_cc_initialize(context, ccache, ctx->source); 179178825Sdfr if (kret) { 180178825Sdfr ctx->flags &= ~GSS_C_DELEG_FLAG; 181178825Sdfr goto out; 182178825Sdfr } 183233294Sstas 184178825Sdfr krb5_auth_con_removeflags(context, 185178825Sdfr ctx->auth_context, 186178825Sdfr KRB5_AUTH_CONTEXT_DO_TIME, 187178825Sdfr &ac_flags); 188178825Sdfr kret = krb5_rd_cred2(context, 189178825Sdfr ctx->auth_context, 190178825Sdfr ccache, 191178825Sdfr &ctx->fwd_data); 192178825Sdfr krb5_auth_con_setflags(context, 193178825Sdfr ctx->auth_context, 194178825Sdfr ac_flags); 195178825Sdfr if (kret) { 196178825Sdfr ctx->flags &= ~GSS_C_DELEG_FLAG; 197178825Sdfr ret = GSS_S_FAILURE; 198178825Sdfr *minor_status = kret; 199178825Sdfr goto out; 200178825Sdfr } 201178825Sdfr 202178825Sdfr if (delegated_cred_handle) { 203178825Sdfr gsskrb5_cred handle; 204178825Sdfr 205233294Sstas ret = _gsskrb5_krb5_import_cred(minor_status, 206233294Sstas ccache, 207233294Sstas NULL, 208233294Sstas NULL, 209233294Sstas delegated_cred_handle); 210178825Sdfr if (ret != GSS_S_COMPLETE) 211178825Sdfr goto out; 212178825Sdfr 213178825Sdfr handle = (gsskrb5_cred) *delegated_cred_handle; 214233294Sstas 215178825Sdfr handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; 216178825Sdfr krb5_cc_close(context, ccache); 217178825Sdfr ccache = NULL; 218178825Sdfr } 219178825Sdfr 220178825Sdfrout: 221178825Sdfr if (ccache) { 222178825Sdfr /* Don't destroy the default cred cache */ 223178825Sdfr if (delegated_cred_handle == NULL) 224178825Sdfr krb5_cc_close(context, ccache); 225178825Sdfr else 226178825Sdfr krb5_cc_destroy(context, ccache); 227178825Sdfr } 228178825Sdfr return ret; 229178825Sdfr} 230178825Sdfr 231178825Sdfrstatic OM_uint32 232178825Sdfrgsskrb5_acceptor_ready(OM_uint32 * minor_status, 233178825Sdfr gsskrb5_ctx ctx, 234178825Sdfr krb5_context context, 235178825Sdfr gss_cred_id_t *delegated_cred_handle) 236178825Sdfr{ 237178825Sdfr OM_uint32 ret; 238178825Sdfr int32_t seq_number; 239178825Sdfr int is_cfx = 0; 240178825Sdfr 241233294Sstas krb5_auth_con_getremoteseqnumber (context, 242233294Sstas ctx->auth_context, 243233294Sstas &seq_number); 244178825Sdfr 245233294Sstas _gsskrb5i_is_cfx(context, ctx, 1); 246233294Sstas is_cfx = (ctx->more_flags & IS_CFX); 247178825Sdfr 248178825Sdfr ret = _gssapi_msg_order_create(minor_status, 249178825Sdfr &ctx->order, 250178825Sdfr _gssapi_msg_order_f(ctx->flags), 251178825Sdfr seq_number, 0, is_cfx); 252178825Sdfr if (ret) 253178825Sdfr return ret; 254178825Sdfr 255233294Sstas /* 256178825Sdfr * If requested, set local sequence num to remote sequence if this 257178825Sdfr * isn't a mutual authentication context 258178825Sdfr */ 259178825Sdfr if (!(ctx->flags & GSS_C_MUTUAL_FLAG) && _gssapi_msg_order_f(ctx->flags)) { 260178825Sdfr krb5_auth_con_setlocalseqnumber(context, 261178825Sdfr ctx->auth_context, 262178825Sdfr seq_number); 263178825Sdfr } 264178825Sdfr 265178825Sdfr /* 266178825Sdfr * We should handle the delegation ticket, in case it's there 267178825Sdfr */ 268178825Sdfr if (ctx->fwd_data.length > 0 && (ctx->flags & GSS_C_DELEG_FLAG)) { 269178825Sdfr ret = gsskrb5_accept_delegated_token(minor_status, 270178825Sdfr ctx, 271178825Sdfr context, 272178825Sdfr delegated_cred_handle); 273178825Sdfr if (ret) 274178825Sdfr return ret; 275178825Sdfr } else { 276178825Sdfr /* Well, looks like it wasn't there after all */ 277178825Sdfr ctx->flags &= ~GSS_C_DELEG_FLAG; 278178825Sdfr } 279178825Sdfr 280178825Sdfr ctx->state = ACCEPTOR_READY; 281178825Sdfr ctx->more_flags |= OPEN; 282178825Sdfr 283178825Sdfr return GSS_S_COMPLETE; 284178825Sdfr} 285178825Sdfr 286178825Sdfrstatic OM_uint32 287233294Sstassend_error_token(OM_uint32 *minor_status, 288233294Sstas krb5_context context, 289233294Sstas krb5_error_code kret, 290233294Sstas krb5_principal server, 291233294Sstas krb5_data *indata, 292233294Sstas gss_buffer_t output_token) 293233294Sstas{ 294233294Sstas krb5_principal ap_req_server = NULL; 295233294Sstas krb5_error_code ret; 296233294Sstas krb5_data outbuf; 297233294Sstas /* this e_data value encodes KERB_AP_ERR_TYPE_SKEW_RECOVERY which 298233294Sstas tells windows to try again with the corrected timestamp. See 299233294Sstas [MS-KILE] 2.2.1 KERB-ERROR-DATA */ 300233294Sstas krb5_data e_data = { 7, rk_UNCONST("\x30\x05\xa1\x03\x02\x01\x02") }; 301233294Sstas 302233294Sstas /* build server from request if the acceptor had not selected one */ 303233294Sstas if (server == NULL) { 304233294Sstas AP_REQ ap_req; 305233294Sstas 306233294Sstas ret = krb5_decode_ap_req(context, indata, &ap_req); 307233294Sstas if (ret) { 308233294Sstas *minor_status = ret; 309233294Sstas return GSS_S_FAILURE; 310233294Sstas } 311233294Sstas ret = _krb5_principalname2krb5_principal(context, 312233294Sstas &ap_req_server, 313233294Sstas ap_req.ticket.sname, 314233294Sstas ap_req.ticket.realm); 315233294Sstas free_AP_REQ(&ap_req); 316233294Sstas if (ret) { 317233294Sstas *minor_status = ret; 318233294Sstas return GSS_S_FAILURE; 319233294Sstas } 320233294Sstas server = ap_req_server; 321233294Sstas } 322233294Sstas 323233294Sstas ret = krb5_mk_error(context, kret, NULL, &e_data, NULL, 324233294Sstas server, NULL, NULL, &outbuf); 325233294Sstas if (ap_req_server) 326233294Sstas krb5_free_principal(context, ap_req_server); 327233294Sstas if (ret) { 328233294Sstas *minor_status = ret; 329233294Sstas return GSS_S_FAILURE; 330233294Sstas } 331233294Sstas 332233294Sstas ret = _gsskrb5_encapsulate(minor_status, 333233294Sstas &outbuf, 334233294Sstas output_token, 335233294Sstas "\x03\x00", 336233294Sstas GSS_KRB5_MECHANISM); 337233294Sstas krb5_data_free (&outbuf); 338233294Sstas if (ret) 339233294Sstas return ret; 340233294Sstas 341233294Sstas *minor_status = 0; 342233294Sstas return GSS_S_CONTINUE_NEEDED; 343233294Sstas} 344233294Sstas 345233294Sstas 346233294Sstasstatic OM_uint32 347178825Sdfrgsskrb5_acceptor_start(OM_uint32 * minor_status, 348178825Sdfr gsskrb5_ctx ctx, 349178825Sdfr krb5_context context, 350178825Sdfr const gss_cred_id_t acceptor_cred_handle, 351178825Sdfr const gss_buffer_t input_token_buffer, 352178825Sdfr const gss_channel_bindings_t input_chan_bindings, 353178825Sdfr gss_name_t * src_name, 354178825Sdfr gss_OID * mech_type, 355178825Sdfr gss_buffer_t output_token, 356178825Sdfr OM_uint32 * ret_flags, 357178825Sdfr OM_uint32 * time_rec, 358178825Sdfr gss_cred_id_t * delegated_cred_handle) 359178825Sdfr{ 360178825Sdfr krb5_error_code kret; 361178825Sdfr OM_uint32 ret = GSS_S_COMPLETE; 362178825Sdfr krb5_data indata; 363178825Sdfr krb5_flags ap_options; 364178825Sdfr krb5_keytab keytab = NULL; 365178825Sdfr int is_cfx = 0; 366178825Sdfr const gsskrb5_cred acceptor_cred = (gsskrb5_cred)acceptor_cred_handle; 367178825Sdfr 368178825Sdfr /* 369178825Sdfr * We may, or may not, have an escapsulation. 370178825Sdfr */ 371178825Sdfr ret = _gsskrb5_decapsulate (minor_status, 372178825Sdfr input_token_buffer, 373178825Sdfr &indata, 374178825Sdfr "\x01\x00", 375178825Sdfr GSS_KRB5_MECHANISM); 376178825Sdfr 377178825Sdfr if (ret) { 378178825Sdfr /* Assume that there is no OID wrapping. */ 379178825Sdfr indata.length = input_token_buffer->length; 380178825Sdfr indata.data = input_token_buffer->value; 381178825Sdfr } 382178825Sdfr 383178825Sdfr /* 384178825Sdfr * We need to get our keytab 385178825Sdfr */ 386178825Sdfr if (acceptor_cred == NULL) { 387178825Sdfr if (_gsskrb5_keytab != NULL) 388178825Sdfr keytab = _gsskrb5_keytab; 389178825Sdfr } else if (acceptor_cred->keytab != NULL) { 390178825Sdfr keytab = acceptor_cred->keytab; 391178825Sdfr } 392233294Sstas 393178825Sdfr /* 394178825Sdfr * We need to check the ticket and create the AP-REP packet 395178825Sdfr */ 396178825Sdfr 397178825Sdfr { 398178825Sdfr krb5_rd_req_in_ctx in = NULL; 399178825Sdfr krb5_rd_req_out_ctx out = NULL; 400233294Sstas krb5_principal server = NULL; 401178825Sdfr 402233294Sstas if (acceptor_cred) 403233294Sstas server = acceptor_cred->principal; 404233294Sstas 405178825Sdfr kret = krb5_rd_req_in_ctx_alloc(context, &in); 406178825Sdfr if (kret == 0) 407178825Sdfr kret = krb5_rd_req_in_set_keytab(context, in, keytab); 408178825Sdfr if (kret) { 409178825Sdfr if (in) 410178825Sdfr krb5_rd_req_in_ctx_free(context, in); 411178825Sdfr *minor_status = kret; 412233294Sstas return GSS_S_FAILURE; 413178825Sdfr } 414178825Sdfr 415178825Sdfr kret = krb5_rd_req_ctx(context, 416178825Sdfr &ctx->auth_context, 417178825Sdfr &indata, 418233294Sstas server, 419178825Sdfr in, &out); 420178825Sdfr krb5_rd_req_in_ctx_free(context, in); 421233294Sstas if (kret == KRB5KRB_AP_ERR_SKEW || kret == KRB5KRB_AP_ERR_TKT_NYV) { 422233294Sstas /* 423233294Sstas * No reply in non-MUTUAL mode, but we don't know that its 424233294Sstas * non-MUTUAL mode yet, thats inside the 8003 checksum, so 425233294Sstas * lets only send the error token on clock skew, that 426233294Sstas * limit when send error token for non-MUTUAL. 427233294Sstas */ 428233294Sstas return send_error_token(minor_status, context, kret, 429233294Sstas server, &indata, output_token); 430233294Sstas } else if (kret) { 431178825Sdfr *minor_status = kret; 432233294Sstas return GSS_S_FAILURE; 433178825Sdfr } 434178825Sdfr 435178825Sdfr /* 436233294Sstas * we need to remember some data on the context_handle. 437178825Sdfr */ 438178825Sdfr kret = krb5_rd_req_out_get_ap_req_options(context, out, 439178825Sdfr &ap_options); 440178825Sdfr if (kret == 0) 441233294Sstas kret = krb5_rd_req_out_get_ticket(context, out, 442178825Sdfr &ctx->ticket); 443178825Sdfr if (kret == 0) 444178825Sdfr kret = krb5_rd_req_out_get_keyblock(context, out, 445178825Sdfr &ctx->service_keyblock); 446178825Sdfr ctx->lifetime = ctx->ticket->ticket.endtime; 447178825Sdfr 448178825Sdfr krb5_rd_req_out_ctx_free(context, out); 449178825Sdfr if (kret) { 450178825Sdfr ret = GSS_S_FAILURE; 451178825Sdfr *minor_status = kret; 452178825Sdfr return ret; 453178825Sdfr } 454178825Sdfr } 455233294Sstas 456233294Sstas 457178825Sdfr /* 458178825Sdfr * We need to copy the principal names to the context and the 459178825Sdfr * calling layer. 460178825Sdfr */ 461178825Sdfr kret = krb5_copy_principal(context, 462178825Sdfr ctx->ticket->client, 463178825Sdfr &ctx->source); 464178825Sdfr if (kret) { 465178825Sdfr ret = GSS_S_FAILURE; 466178825Sdfr *minor_status = kret; 467178825Sdfr } 468178825Sdfr 469233294Sstas kret = krb5_copy_principal(context, 470178825Sdfr ctx->ticket->server, 471178825Sdfr &ctx->target); 472178825Sdfr if (kret) { 473178825Sdfr ret = GSS_S_FAILURE; 474178825Sdfr *minor_status = kret; 475178825Sdfr return ret; 476178825Sdfr } 477233294Sstas 478178825Sdfr /* 479178825Sdfr * We need to setup some compat stuff, this assumes that 480178825Sdfr * context_handle->target is already set. 481178825Sdfr */ 482178825Sdfr ret = _gss_DES3_get_mic_compat(minor_status, ctx, context); 483178825Sdfr if (ret) 484178825Sdfr return ret; 485178825Sdfr 486178825Sdfr if (src_name != NULL) { 487178825Sdfr kret = krb5_copy_principal (context, 488178825Sdfr ctx->ticket->client, 489178825Sdfr (gsskrb5_name*)src_name); 490178825Sdfr if (kret) { 491178825Sdfr ret = GSS_S_FAILURE; 492178825Sdfr *minor_status = kret; 493178825Sdfr return ret; 494178825Sdfr } 495178825Sdfr } 496178825Sdfr 497178825Sdfr /* 498178825Sdfr * We need to get the flags out of the 8003 checksum. 499178825Sdfr */ 500233294Sstas 501178825Sdfr { 502178825Sdfr krb5_authenticator authenticator; 503233294Sstas 504178825Sdfr kret = krb5_auth_con_getauthenticator(context, 505178825Sdfr ctx->auth_context, 506178825Sdfr &authenticator); 507178825Sdfr if(kret) { 508178825Sdfr ret = GSS_S_FAILURE; 509178825Sdfr *minor_status = kret; 510178825Sdfr return ret; 511178825Sdfr } 512178825Sdfr 513233294Sstas if (authenticator->cksum == NULL) { 514233294Sstas krb5_free_authenticator(context, &authenticator); 515233294Sstas *minor_status = 0; 516233294Sstas return GSS_S_BAD_BINDINGS; 517233294Sstas } 518233294Sstas 519178825Sdfr if (authenticator->cksum->cksumtype == CKSUMTYPE_GSSAPI) { 520178825Sdfr ret = _gsskrb5_verify_8003_checksum(minor_status, 521178825Sdfr input_chan_bindings, 522178825Sdfr authenticator->cksum, 523178825Sdfr &ctx->flags, 524178825Sdfr &ctx->fwd_data); 525178825Sdfr 526178825Sdfr krb5_free_authenticator(context, &authenticator); 527178825Sdfr if (ret) { 528178825Sdfr return ret; 529178825Sdfr } 530178825Sdfr } else { 531178825Sdfr krb5_crypto crypto; 532178825Sdfr 533233294Sstas kret = krb5_crypto_init(context, 534233294Sstas ctx->auth_context->keyblock, 535178825Sdfr 0, &crypto); 536178825Sdfr if(kret) { 537178825Sdfr krb5_free_authenticator(context, &authenticator); 538178825Sdfr 539178825Sdfr ret = GSS_S_FAILURE; 540178825Sdfr *minor_status = kret; 541178825Sdfr return ret; 542178825Sdfr } 543178825Sdfr 544233294Sstas /* 545178825Sdfr * Windows accepts Samba3's use of a kerberos, rather than 546233294Sstas * GSSAPI checksum here 547178825Sdfr */ 548178825Sdfr 549178825Sdfr kret = krb5_verify_checksum(context, 550178825Sdfr crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0, 551178825Sdfr authenticator->cksum); 552178825Sdfr krb5_free_authenticator(context, &authenticator); 553178825Sdfr krb5_crypto_destroy(context, crypto); 554178825Sdfr 555178825Sdfr if(kret) { 556178825Sdfr ret = GSS_S_BAD_SIG; 557178825Sdfr *minor_status = kret; 558178825Sdfr return ret; 559178825Sdfr } 560178825Sdfr 561233294Sstas /* 562233294Sstas * Samba style get some flags (but not DCE-STYLE), use 563233294Sstas * ap_options to guess the mutual flag. 564178825Sdfr */ 565233294Sstas ctx->flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG; 566233294Sstas if (ap_options & AP_OPTS_MUTUAL_REQUIRED) 567233294Sstas ctx->flags |= GSS_C_MUTUAL_FLAG; 568178825Sdfr } 569178825Sdfr } 570233294Sstas 571178825Sdfr if(ctx->flags & GSS_C_MUTUAL_FLAG) { 572178825Sdfr krb5_data outbuf; 573233294Sstas int use_subkey = 0; 574233294Sstas 575233294Sstas _gsskrb5i_is_cfx(context, ctx, 1); 576233294Sstas is_cfx = (ctx->more_flags & IS_CFX); 577233294Sstas 578233294Sstas if (is_cfx || (ap_options & AP_OPTS_USE_SUBKEY)) { 579233294Sstas use_subkey = 1; 580233294Sstas } else { 581233294Sstas krb5_keyblock *rkey; 582233294Sstas 583233294Sstas /* 584233294Sstas * If there is a initiator subkey, copy that to acceptor 585233294Sstas * subkey to match Windows behavior 586233294Sstas */ 587233294Sstas kret = krb5_auth_con_getremotesubkey(context, 588233294Sstas ctx->auth_context, 589233294Sstas &rkey); 590233294Sstas if (kret == 0) { 591233294Sstas kret = krb5_auth_con_setlocalsubkey(context, 592233294Sstas ctx->auth_context, 593233294Sstas rkey); 594233294Sstas if (kret == 0) 595233294Sstas use_subkey = 1; 596233294Sstas krb5_free_keyblock(context, rkey); 597233294Sstas } 598233294Sstas } 599233294Sstas if (use_subkey) { 600178825Sdfr ctx->more_flags |= ACCEPTOR_SUBKEY; 601233294Sstas krb5_auth_con_addflags(context, ctx->auth_context, 602233294Sstas KRB5_AUTH_CONTEXT_USE_SUBKEY, 603233294Sstas NULL); 604178825Sdfr } 605233294Sstas 606178825Sdfr kret = krb5_mk_rep(context, 607178825Sdfr ctx->auth_context, 608178825Sdfr &outbuf); 609178825Sdfr if (kret) { 610178825Sdfr *minor_status = kret; 611178825Sdfr return GSS_S_FAILURE; 612178825Sdfr } 613233294Sstas 614178825Sdfr if (IS_DCE_STYLE(ctx)) { 615178825Sdfr output_token->length = outbuf.length; 616178825Sdfr output_token->value = outbuf.data; 617178825Sdfr } else { 618178825Sdfr ret = _gsskrb5_encapsulate(minor_status, 619178825Sdfr &outbuf, 620178825Sdfr output_token, 621178825Sdfr "\x02\x00", 622178825Sdfr GSS_KRB5_MECHANISM); 623178825Sdfr krb5_data_free (&outbuf); 624178825Sdfr if (ret) 625178825Sdfr return ret; 626178825Sdfr } 627178825Sdfr } 628233294Sstas 629178825Sdfr ctx->flags |= GSS_C_TRANS_FLAG; 630178825Sdfr 631178825Sdfr /* Remember the flags */ 632233294Sstas 633178825Sdfr ctx->lifetime = ctx->ticket->ticket.endtime; 634178825Sdfr ctx->more_flags |= OPEN; 635233294Sstas 636178825Sdfr if (mech_type) 637178825Sdfr *mech_type = GSS_KRB5_MECHANISM; 638233294Sstas 639178825Sdfr if (time_rec) { 640178825Sdfr ret = _gsskrb5_lifetime_left(minor_status, 641178825Sdfr context, 642178825Sdfr ctx->lifetime, 643178825Sdfr time_rec); 644178825Sdfr if (ret) { 645178825Sdfr return ret; 646178825Sdfr } 647178825Sdfr } 648178825Sdfr 649178825Sdfr /* 650178825Sdfr * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from 651178825Sdfr * the client. 652178825Sdfr */ 653178825Sdfr if (IS_DCE_STYLE(ctx)) { 654178825Sdfr /* 655178825Sdfr * Return flags to caller, but we haven't processed 656178825Sdfr * delgations yet 657178825Sdfr */ 658178825Sdfr if (ret_flags) 659178825Sdfr *ret_flags = (ctx->flags & ~GSS_C_DELEG_FLAG); 660178825Sdfr 661178825Sdfr ctx->state = ACCEPTOR_WAIT_FOR_DCESTYLE; 662178825Sdfr return GSS_S_CONTINUE_NEEDED; 663178825Sdfr } 664178825Sdfr 665233294Sstas ret = gsskrb5_acceptor_ready(minor_status, ctx, context, 666178825Sdfr delegated_cred_handle); 667178825Sdfr 668178825Sdfr if (ret_flags) 669178825Sdfr *ret_flags = ctx->flags; 670178825Sdfr 671178825Sdfr return ret; 672178825Sdfr} 673178825Sdfr 674178825Sdfrstatic OM_uint32 675178825Sdfracceptor_wait_for_dcestyle(OM_uint32 * minor_status, 676178825Sdfr gsskrb5_ctx ctx, 677178825Sdfr krb5_context context, 678178825Sdfr const gss_cred_id_t acceptor_cred_handle, 679178825Sdfr const gss_buffer_t input_token_buffer, 680178825Sdfr const gss_channel_bindings_t input_chan_bindings, 681178825Sdfr gss_name_t * src_name, 682178825Sdfr gss_OID * mech_type, 683178825Sdfr gss_buffer_t output_token, 684178825Sdfr OM_uint32 * ret_flags, 685178825Sdfr OM_uint32 * time_rec, 686178825Sdfr gss_cred_id_t * delegated_cred_handle) 687178825Sdfr{ 688178825Sdfr OM_uint32 ret; 689178825Sdfr krb5_error_code kret; 690178825Sdfr krb5_data inbuf; 691178825Sdfr int32_t r_seq_number, l_seq_number; 692233294Sstas 693233294Sstas /* 694178825Sdfr * We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP 695178825Sdfr */ 696178825Sdfr 697178825Sdfr inbuf.length = input_token_buffer->length; 698178825Sdfr inbuf.data = input_token_buffer->value; 699178825Sdfr 700233294Sstas /* 701178825Sdfr * We need to remeber the old remote seq_number, then check if the 702178825Sdfr * client has replied with our local seq_number, and then reset 703178825Sdfr * the remote seq_number to the old value 704178825Sdfr */ 705178825Sdfr { 706178825Sdfr kret = krb5_auth_con_getlocalseqnumber(context, 707178825Sdfr ctx->auth_context, 708178825Sdfr &l_seq_number); 709178825Sdfr if (kret) { 710178825Sdfr *minor_status = kret; 711178825Sdfr return GSS_S_FAILURE; 712178825Sdfr } 713178825Sdfr 714233294Sstas kret = krb5_auth_con_getremoteseqnumber(context, 715233294Sstas ctx->auth_context, 716233294Sstas &r_seq_number); 717178825Sdfr if (kret) { 718178825Sdfr *minor_status = kret; 719178825Sdfr return GSS_S_FAILURE; 720178825Sdfr } 721178825Sdfr 722178825Sdfr kret = krb5_auth_con_setremoteseqnumber(context, 723178825Sdfr ctx->auth_context, 724178825Sdfr l_seq_number); 725178825Sdfr if (kret) { 726178825Sdfr *minor_status = kret; 727178825Sdfr return GSS_S_FAILURE; 728178825Sdfr } 729178825Sdfr } 730178825Sdfr 731233294Sstas /* 732178825Sdfr * We need to verify the AP_REP, but we need to flag that this is 733178825Sdfr * DCE_STYLE, so don't check the timestamps this time, but put the 734178825Sdfr * flag DO_TIME back afterward. 735233294Sstas */ 736178825Sdfr { 737178825Sdfr krb5_ap_rep_enc_part *repl; 738178825Sdfr int32_t auth_flags; 739233294Sstas 740178825Sdfr krb5_auth_con_removeflags(context, 741178825Sdfr ctx->auth_context, 742178825Sdfr KRB5_AUTH_CONTEXT_DO_TIME, 743178825Sdfr &auth_flags); 744178825Sdfr 745178825Sdfr kret = krb5_rd_rep(context, ctx->auth_context, &inbuf, &repl); 746178825Sdfr if (kret) { 747178825Sdfr *minor_status = kret; 748178825Sdfr return GSS_S_FAILURE; 749178825Sdfr } 750178825Sdfr krb5_free_ap_rep_enc_part(context, repl); 751178825Sdfr krb5_auth_con_setflags(context, ctx->auth_context, auth_flags); 752178825Sdfr } 753178825Sdfr 754178825Sdfr /* We need to check the liftime */ 755178825Sdfr { 756178825Sdfr OM_uint32 lifetime_rec; 757178825Sdfr 758178825Sdfr ret = _gsskrb5_lifetime_left(minor_status, 759178825Sdfr context, 760178825Sdfr ctx->lifetime, 761178825Sdfr &lifetime_rec); 762178825Sdfr if (ret) { 763178825Sdfr return ret; 764178825Sdfr } 765178825Sdfr if (lifetime_rec == 0) { 766178825Sdfr return GSS_S_CONTEXT_EXPIRED; 767178825Sdfr } 768233294Sstas 769178825Sdfr if (time_rec) *time_rec = lifetime_rec; 770178825Sdfr } 771178825Sdfr 772178825Sdfr /* We need to give the caller the flags which are in use */ 773178825Sdfr if (ret_flags) *ret_flags = ctx->flags; 774178825Sdfr 775178825Sdfr if (src_name) { 776178825Sdfr kret = krb5_copy_principal(context, 777178825Sdfr ctx->source, 778178825Sdfr (gsskrb5_name*)src_name); 779178825Sdfr if (kret) { 780178825Sdfr *minor_status = kret; 781178825Sdfr return GSS_S_FAILURE; 782178825Sdfr } 783178825Sdfr } 784178825Sdfr 785178825Sdfr /* 786178825Sdfr * After the krb5_rd_rep() the remote and local seq_number should 787178825Sdfr * be the same, because the client just replies the seq_number 788178825Sdfr * from our AP-REP in its AP-REP, but then the client uses the 789178825Sdfr * seq_number from its AP-REQ for GSS_wrap() 790178825Sdfr */ 791178825Sdfr { 792178825Sdfr int32_t tmp_r_seq_number, tmp_l_seq_number; 793178825Sdfr 794233294Sstas kret = krb5_auth_con_getremoteseqnumber(context, 795233294Sstas ctx->auth_context, 796233294Sstas &tmp_r_seq_number); 797178825Sdfr if (kret) { 798178825Sdfr *minor_status = kret; 799178825Sdfr return GSS_S_FAILURE; 800178825Sdfr } 801178825Sdfr 802178825Sdfr kret = krb5_auth_con_getlocalseqnumber(context, 803178825Sdfr ctx->auth_context, 804178825Sdfr &tmp_l_seq_number); 805178825Sdfr if (kret) { 806178825Sdfr 807178825Sdfr *minor_status = kret; 808178825Sdfr return GSS_S_FAILURE; 809178825Sdfr } 810178825Sdfr 811178825Sdfr /* 812178825Sdfr * Here we check if the client has responsed with our local seq_number, 813178825Sdfr */ 814178825Sdfr if (tmp_r_seq_number != tmp_l_seq_number) { 815178825Sdfr return GSS_S_UNSEQ_TOKEN; 816178825Sdfr } 817178825Sdfr } 818178825Sdfr 819178825Sdfr /* 820178825Sdfr * We need to reset the remote seq_number, because the client will use, 821178825Sdfr * the old one for the GSS_wrap() calls 822178825Sdfr */ 823178825Sdfr { 824178825Sdfr kret = krb5_auth_con_setremoteseqnumber(context, 825178825Sdfr ctx->auth_context, 826233294Sstas r_seq_number); 827178825Sdfr if (kret) { 828178825Sdfr *minor_status = kret; 829178825Sdfr return GSS_S_FAILURE; 830178825Sdfr } 831178825Sdfr } 832178825Sdfr 833233294Sstas return gsskrb5_acceptor_ready(minor_status, ctx, context, 834178825Sdfr delegated_cred_handle); 835178825Sdfr} 836178825Sdfr 837178825Sdfr 838233294SstasOM_uint32 GSSAPI_CALLCONV 839178825Sdfr_gsskrb5_accept_sec_context(OM_uint32 * minor_status, 840178825Sdfr gss_ctx_id_t * context_handle, 841178825Sdfr const gss_cred_id_t acceptor_cred_handle, 842178825Sdfr const gss_buffer_t input_token_buffer, 843178825Sdfr const gss_channel_bindings_t input_chan_bindings, 844178825Sdfr gss_name_t * src_name, 845178825Sdfr gss_OID * mech_type, 846178825Sdfr gss_buffer_t output_token, 847178825Sdfr OM_uint32 * ret_flags, 848178825Sdfr OM_uint32 * time_rec, 849178825Sdfr gss_cred_id_t * delegated_cred_handle) 850178825Sdfr{ 851178825Sdfr krb5_context context; 852178825Sdfr OM_uint32 ret; 853178825Sdfr gsskrb5_ctx ctx; 854178825Sdfr 855178825Sdfr GSSAPI_KRB5_INIT(&context); 856178825Sdfr 857178825Sdfr output_token->length = 0; 858178825Sdfr output_token->value = NULL; 859178825Sdfr 860178825Sdfr if (src_name != NULL) 861178825Sdfr *src_name = NULL; 862178825Sdfr if (mech_type) 863178825Sdfr *mech_type = GSS_KRB5_MECHANISM; 864178825Sdfr 865178825Sdfr if (*context_handle == GSS_C_NO_CONTEXT) { 866178825Sdfr ret = _gsskrb5_create_ctx(minor_status, 867178825Sdfr context_handle, 868178825Sdfr context, 869178825Sdfr input_chan_bindings, 870178825Sdfr ACCEPTOR_START); 871178825Sdfr if (ret) 872178825Sdfr return ret; 873178825Sdfr } 874233294Sstas 875178825Sdfr ctx = (gsskrb5_ctx)*context_handle; 876178825Sdfr 877233294Sstas 878178825Sdfr /* 879233294Sstas * TODO: check the channel_bindings 880178825Sdfr * (above just sets them to krb5 layer) 881178825Sdfr */ 882178825Sdfr 883178825Sdfr HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 884233294Sstas 885178825Sdfr switch (ctx->state) { 886178825Sdfr case ACCEPTOR_START: 887178825Sdfr ret = gsskrb5_acceptor_start(minor_status, 888178825Sdfr ctx, 889178825Sdfr context, 890178825Sdfr acceptor_cred_handle, 891178825Sdfr input_token_buffer, 892178825Sdfr input_chan_bindings, 893178825Sdfr src_name, 894178825Sdfr mech_type, 895178825Sdfr output_token, 896178825Sdfr ret_flags, 897178825Sdfr time_rec, 898178825Sdfr delegated_cred_handle); 899178825Sdfr break; 900178825Sdfr case ACCEPTOR_WAIT_FOR_DCESTYLE: 901178825Sdfr ret = acceptor_wait_for_dcestyle(minor_status, 902178825Sdfr ctx, 903178825Sdfr context, 904178825Sdfr acceptor_cred_handle, 905178825Sdfr input_token_buffer, 906178825Sdfr input_chan_bindings, 907178825Sdfr src_name, 908178825Sdfr mech_type, 909178825Sdfr output_token, 910178825Sdfr ret_flags, 911178825Sdfr time_rec, 912178825Sdfr delegated_cred_handle); 913178825Sdfr break; 914178825Sdfr case ACCEPTOR_READY: 915233294Sstas /* 916178825Sdfr * If we get there, the caller have called 917178825Sdfr * gss_accept_sec_context() one time too many. 918178825Sdfr */ 919178825Sdfr ret = GSS_S_BAD_STATUS; 920178825Sdfr break; 921178825Sdfr default: 922178825Sdfr /* TODO: is this correct here? --metze */ 923178825Sdfr ret = GSS_S_BAD_STATUS; 924178825Sdfr break; 925178825Sdfr } 926233294Sstas 927178825Sdfr HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 928233294Sstas 929178825Sdfr if (GSS_ERROR(ret)) { 930178825Sdfr OM_uint32 min2; 931178825Sdfr _gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER); 932178825Sdfr } 933178825Sdfr 934178825Sdfr return ret; 935178825Sdfr} 936