1178825Sdfr/* 2233294Sstas * Copyright (c) 1997 - 2004 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4178825Sdfr * Portions Copyright (c) 2004 PADL Software Pty Ltd. 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 "spnego_locl.h" 35178825Sdfr 36178825Sdfr/* 37233294Sstas * Is target_name an sane target for `mech��. 38178825Sdfr */ 39178825Sdfr 40178825Sdfrstatic OM_uint32 41178825Sdfrinitiator_approved(gss_name_t target_name, gss_OID mech) 42178825Sdfr{ 43178825Sdfr OM_uint32 min_stat, maj_stat; 44178825Sdfr gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; 45178825Sdfr gss_buffer_desc out; 46233294Sstas 47178825Sdfr maj_stat = gss_init_sec_context(&min_stat, 48178825Sdfr GSS_C_NO_CREDENTIAL, 49178825Sdfr &ctx, 50178825Sdfr target_name, 51178825Sdfr mech, 52178825Sdfr 0, 53178825Sdfr GSS_C_INDEFINITE, 54178825Sdfr GSS_C_NO_CHANNEL_BINDINGS, 55178825Sdfr GSS_C_NO_BUFFER, 56178825Sdfr NULL, 57178825Sdfr &out, 58178825Sdfr NULL, 59178825Sdfr NULL); 60233294Sstas if (GSS_ERROR(maj_stat)) { 61233294Sstas gss_mg_collect_error(mech, maj_stat, min_stat); 62178825Sdfr return GSS_S_BAD_MECH; 63233294Sstas } 64178825Sdfr gss_release_buffer(&min_stat, &out); 65178825Sdfr gss_delete_sec_context(&min_stat, &ctx, NULL); 66178825Sdfr 67178825Sdfr return GSS_S_COMPLETE; 68178825Sdfr} 69178825Sdfr 70178825Sdfr/* 71178825Sdfr * Send a reply. Note that we only need to send a reply if we 72178825Sdfr * need to send a MIC or a mechanism token. Otherwise, we can 73178825Sdfr * return an empty buffer. 74178825Sdfr * 75178825Sdfr * The return value of this will be returned to the API, so it 76178825Sdfr * must return GSS_S_CONTINUE_NEEDED if a token was generated. 77178825Sdfr */ 78178825Sdfrstatic OM_uint32 79178825Sdfrspnego_reply_internal(OM_uint32 *minor_status, 80178825Sdfr gssspnego_ctx context_handle, 81178825Sdfr const gss_buffer_t mech_buf, 82178825Sdfr gss_buffer_t mech_token, 83178825Sdfr gss_buffer_t output_token) 84178825Sdfr{ 85178825Sdfr NegotiationToken nt; 86178825Sdfr gss_buffer_desc mic_buf; 87178825Sdfr OM_uint32 ret; 88178825Sdfr size_t size; 89178825Sdfr 90178825Sdfr if (mech_buf == GSS_C_NO_BUFFER && mech_token->length == 0) { 91178825Sdfr output_token->length = 0; 92178825Sdfr output_token->value = NULL; 93178825Sdfr 94178825Sdfr return context_handle->open ? GSS_S_COMPLETE : GSS_S_FAILURE; 95178825Sdfr } 96178825Sdfr 97178825Sdfr memset(&nt, 0, sizeof(nt)); 98178825Sdfr 99178825Sdfr nt.element = choice_NegotiationToken_negTokenResp; 100178825Sdfr 101178825Sdfr ALLOC(nt.u.negTokenResp.negResult, 1); 102178825Sdfr if (nt.u.negTokenResp.negResult == NULL) { 103178825Sdfr *minor_status = ENOMEM; 104178825Sdfr return GSS_S_FAILURE; 105178825Sdfr } 106178825Sdfr 107178825Sdfr nt.u.negTokenResp.supportedMech = NULL; 108178825Sdfr 109178825Sdfr output_token->length = 0; 110178825Sdfr output_token->value = NULL; 111178825Sdfr 112178825Sdfr if (mech_token->length == 0) { 113178825Sdfr nt.u.negTokenResp.responseToken = NULL; 114178825Sdfr *(nt.u.negTokenResp.negResult) = accept_completed; 115178825Sdfr } else { 116178825Sdfr ALLOC(nt.u.negTokenResp.responseToken, 1); 117178825Sdfr if (nt.u.negTokenResp.responseToken == NULL) { 118178825Sdfr free_NegotiationToken(&nt); 119178825Sdfr *minor_status = ENOMEM; 120178825Sdfr return GSS_S_FAILURE; 121178825Sdfr } 122178825Sdfr nt.u.negTokenResp.responseToken->length = mech_token->length; 123178825Sdfr nt.u.negTokenResp.responseToken->data = mech_token->value; 124178825Sdfr mech_token->length = 0; 125178825Sdfr mech_token->value = NULL; 126178825Sdfr 127178825Sdfr *(nt.u.negTokenResp.negResult) = accept_incomplete; 128178825Sdfr } 129178825Sdfr 130178825Sdfr if (mech_buf != GSS_C_NO_BUFFER) { 131178825Sdfr 132178825Sdfr ret = gss_get_mic(minor_status, 133178825Sdfr context_handle->negotiated_ctx_id, 134178825Sdfr 0, 135178825Sdfr mech_buf, 136178825Sdfr &mic_buf); 137178825Sdfr if (ret == GSS_S_COMPLETE) { 138178825Sdfr ALLOC(nt.u.negTokenResp.mechListMIC, 1); 139178825Sdfr if (nt.u.negTokenResp.mechListMIC == NULL) { 140178825Sdfr gss_release_buffer(minor_status, &mic_buf); 141178825Sdfr free_NegotiationToken(&nt); 142178825Sdfr *minor_status = ENOMEM; 143178825Sdfr return GSS_S_FAILURE; 144178825Sdfr } 145178825Sdfr 146178825Sdfr nt.u.negTokenResp.mechListMIC->length = mic_buf.length; 147178825Sdfr nt.u.negTokenResp.mechListMIC->data = mic_buf.value; 148178825Sdfr } else if (ret == GSS_S_UNAVAILABLE) { 149178825Sdfr nt.u.negTokenResp.mechListMIC = NULL; 150178825Sdfr } if (ret) { 151178825Sdfr free_NegotiationToken(&nt); 152178825Sdfr *minor_status = ENOMEM; 153178825Sdfr return GSS_S_FAILURE; 154178825Sdfr } 155178825Sdfr } else { 156178825Sdfr nt.u.negTokenResp.mechListMIC = NULL; 157178825Sdfr } 158178825Sdfr 159178825Sdfr ASN1_MALLOC_ENCODE(NegotiationToken, 160178825Sdfr output_token->value, output_token->length, 161178825Sdfr &nt, &size, ret); 162178825Sdfr if (ret) { 163178825Sdfr free_NegotiationToken(&nt); 164178825Sdfr *minor_status = ret; 165178825Sdfr return GSS_S_FAILURE; 166178825Sdfr } 167178825Sdfr 168178825Sdfr if (*(nt.u.negTokenResp.negResult) == accept_completed) 169178825Sdfr ret = GSS_S_COMPLETE; 170178825Sdfr else 171178825Sdfr ret = GSS_S_CONTINUE_NEEDED; 172178825Sdfr 173178825Sdfr free_NegotiationToken(&nt); 174178825Sdfr return ret; 175178825Sdfr} 176178825Sdfr 177178825Sdfrstatic OM_uint32 178178825Sdfrspnego_initial 179178825Sdfr (OM_uint32 * minor_status, 180233294Sstas gss_cred_id_t cred, 181178825Sdfr gss_ctx_id_t * context_handle, 182178825Sdfr const gss_name_t target_name, 183178825Sdfr const gss_OID mech_type, 184178825Sdfr OM_uint32 req_flags, 185178825Sdfr OM_uint32 time_req, 186178825Sdfr const gss_channel_bindings_t input_chan_bindings, 187178825Sdfr const gss_buffer_t input_token, 188178825Sdfr gss_OID * actual_mech_type, 189178825Sdfr gss_buffer_t output_token, 190178825Sdfr OM_uint32 * ret_flags, 191178825Sdfr OM_uint32 * time_rec 192178825Sdfr ) 193178825Sdfr{ 194178825Sdfr NegTokenInit ni; 195178825Sdfr int ret; 196178825Sdfr OM_uint32 sub, minor; 197178825Sdfr gss_buffer_desc mech_token; 198178825Sdfr u_char *buf; 199178825Sdfr size_t buf_size, buf_len; 200178825Sdfr gss_buffer_desc data; 201178825Sdfr size_t ni_len; 202178825Sdfr gss_ctx_id_t context; 203178825Sdfr gssspnego_ctx ctx; 204178825Sdfr spnego_name name = (spnego_name)target_name; 205178825Sdfr 206178825Sdfr *minor_status = 0; 207178825Sdfr 208178825Sdfr memset (&ni, 0, sizeof(ni)); 209178825Sdfr 210178825Sdfr *context_handle = GSS_C_NO_CONTEXT; 211178825Sdfr 212178825Sdfr if (target_name == GSS_C_NO_NAME) 213178825Sdfr return GSS_S_BAD_NAME; 214178825Sdfr 215178825Sdfr sub = _gss_spnego_alloc_sec_context(&minor, &context); 216178825Sdfr if (GSS_ERROR(sub)) { 217178825Sdfr *minor_status = minor; 218178825Sdfr return sub; 219178825Sdfr } 220178825Sdfr ctx = (gssspnego_ctx)context; 221178825Sdfr 222178825Sdfr HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 223178825Sdfr 224178825Sdfr ctx->local = 1; 225178825Sdfr 226178825Sdfr sub = gss_import_name(&minor, &name->value, &name->type, &ctx->target_name); 227178825Sdfr if (GSS_ERROR(sub)) { 228178825Sdfr *minor_status = minor; 229178825Sdfr _gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER); 230178825Sdfr return sub; 231178825Sdfr } 232178825Sdfr 233233294Sstas sub = _gss_spnego_indicate_mechtypelist(&minor, 234178825Sdfr ctx->target_name, 235178825Sdfr initiator_approved, 236178825Sdfr 0, 237178825Sdfr cred, 238178825Sdfr &ni.mechTypes, 239178825Sdfr &ctx->preferred_mech_type); 240178825Sdfr if (GSS_ERROR(sub)) { 241178825Sdfr *minor_status = minor; 242178825Sdfr _gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER); 243178825Sdfr return sub; 244178825Sdfr } 245178825Sdfr 246178825Sdfr ni.reqFlags = NULL; 247178825Sdfr 248178825Sdfr /* 249178825Sdfr * If we have a credential handle, use it to select the mechanism 250178825Sdfr * that we will use 251178825Sdfr */ 252178825Sdfr 253178825Sdfr /* generate optimistic token */ 254178825Sdfr sub = gss_init_sec_context(&minor, 255233294Sstas cred, 256178825Sdfr &ctx->negotiated_ctx_id, 257178825Sdfr ctx->target_name, 258178825Sdfr ctx->preferred_mech_type, 259178825Sdfr req_flags, 260178825Sdfr time_req, 261178825Sdfr input_chan_bindings, 262178825Sdfr input_token, 263178825Sdfr &ctx->negotiated_mech_type, 264178825Sdfr &mech_token, 265178825Sdfr &ctx->mech_flags, 266178825Sdfr &ctx->mech_time_rec); 267178825Sdfr if (GSS_ERROR(sub)) { 268178825Sdfr free_NegTokenInit(&ni); 269178825Sdfr *minor_status = minor; 270233294Sstas gss_mg_collect_error(ctx->preferred_mech_type, sub, minor); 271178825Sdfr _gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER); 272178825Sdfr return sub; 273178825Sdfr } 274178825Sdfr if (sub == GSS_S_COMPLETE) 275178825Sdfr ctx->maybe_open = 1; 276178825Sdfr 277178825Sdfr if (mech_token.length != 0) { 278178825Sdfr ALLOC(ni.mechToken, 1); 279178825Sdfr if (ni.mechToken == NULL) { 280178825Sdfr free_NegTokenInit(&ni); 281178825Sdfr gss_release_buffer(&minor, &mech_token); 282178825Sdfr _gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER); 283178825Sdfr *minor_status = ENOMEM; 284178825Sdfr return GSS_S_FAILURE; 285178825Sdfr } 286178825Sdfr ni.mechToken->length = mech_token.length; 287178825Sdfr ni.mechToken->data = malloc(mech_token.length); 288178825Sdfr if (ni.mechToken->data == NULL && mech_token.length != 0) { 289178825Sdfr free_NegTokenInit(&ni); 290178825Sdfr gss_release_buffer(&minor, &mech_token); 291178825Sdfr *minor_status = ENOMEM; 292178825Sdfr _gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER); 293178825Sdfr return GSS_S_FAILURE; 294178825Sdfr } 295178825Sdfr memcpy(ni.mechToken->data, mech_token.value, mech_token.length); 296178825Sdfr gss_release_buffer(&minor, &mech_token); 297178825Sdfr } else 298178825Sdfr ni.mechToken = NULL; 299178825Sdfr 300178825Sdfr ni.mechListMIC = NULL; 301178825Sdfr 302178825Sdfr ni_len = length_NegTokenInit(&ni); 303178825Sdfr buf_size = 1 + der_length_len(ni_len) + ni_len; 304178825Sdfr 305178825Sdfr buf = malloc(buf_size); 306178825Sdfr if (buf == NULL) { 307178825Sdfr free_NegTokenInit(&ni); 308178825Sdfr *minor_status = ENOMEM; 309178825Sdfr _gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER); 310178825Sdfr return GSS_S_FAILURE; 311178825Sdfr } 312178825Sdfr 313178825Sdfr ret = encode_NegTokenInit(buf + buf_size - 1, 314178825Sdfr ni_len, 315178825Sdfr &ni, &buf_len); 316178825Sdfr if (ret == 0 && ni_len != buf_len) 317178825Sdfr abort(); 318178825Sdfr 319178825Sdfr if (ret == 0) { 320178825Sdfr size_t tmp; 321178825Sdfr 322178825Sdfr ret = der_put_length_and_tag(buf + buf_size - buf_len - 1, 323178825Sdfr buf_size - buf_len, 324178825Sdfr buf_len, 325178825Sdfr ASN1_C_CONTEXT, 326178825Sdfr CONS, 327178825Sdfr 0, 328178825Sdfr &tmp); 329178825Sdfr if (ret == 0 && tmp + buf_len != buf_size) 330178825Sdfr abort(); 331178825Sdfr } 332178825Sdfr if (ret) { 333178825Sdfr *minor_status = ret; 334178825Sdfr free(buf); 335178825Sdfr free_NegTokenInit(&ni); 336178825Sdfr _gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER); 337178825Sdfr return GSS_S_FAILURE; 338178825Sdfr } 339178825Sdfr 340178825Sdfr data.value = buf; 341178825Sdfr data.length = buf_size; 342178825Sdfr 343178825Sdfr ctx->initiator_mech_types.len = ni.mechTypes.len; 344178825Sdfr ctx->initiator_mech_types.val = ni.mechTypes.val; 345178825Sdfr ni.mechTypes.len = 0; 346178825Sdfr ni.mechTypes.val = NULL; 347233294Sstas 348178825Sdfr free_NegTokenInit(&ni); 349178825Sdfr 350178825Sdfr sub = gss_encapsulate_token(&data, 351178825Sdfr GSS_SPNEGO_MECHANISM, 352178825Sdfr output_token); 353178825Sdfr free (buf); 354178825Sdfr 355178825Sdfr if (sub) { 356178825Sdfr _gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER); 357178825Sdfr return sub; 358178825Sdfr } 359178825Sdfr 360178825Sdfr if (actual_mech_type) 361178825Sdfr *actual_mech_type = ctx->negotiated_mech_type; 362178825Sdfr if (ret_flags) 363178825Sdfr *ret_flags = ctx->mech_flags; 364178825Sdfr if (time_rec) 365178825Sdfr *time_rec = ctx->mech_time_rec; 366178825Sdfr 367178825Sdfr HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 368178825Sdfr 369178825Sdfr *context_handle = context; 370178825Sdfr 371178825Sdfr return GSS_S_CONTINUE_NEEDED; 372178825Sdfr} 373178825Sdfr 374178825Sdfrstatic OM_uint32 375178825Sdfrspnego_reply 376178825Sdfr (OM_uint32 * minor_status, 377233294Sstas const gss_cred_id_t cred, 378178825Sdfr gss_ctx_id_t * context_handle, 379178825Sdfr const gss_name_t target_name, 380178825Sdfr const gss_OID mech_type, 381178825Sdfr OM_uint32 req_flags, 382178825Sdfr OM_uint32 time_req, 383178825Sdfr const gss_channel_bindings_t input_chan_bindings, 384178825Sdfr const gss_buffer_t input_token, 385178825Sdfr gss_OID * actual_mech_type, 386178825Sdfr gss_buffer_t output_token, 387178825Sdfr OM_uint32 * ret_flags, 388178825Sdfr OM_uint32 * time_rec 389178825Sdfr ) 390178825Sdfr{ 391178825Sdfr OM_uint32 ret, minor; 392233294Sstas NegotiationToken resp; 393178825Sdfr gss_OID_desc mech; 394178825Sdfr int require_mic; 395233294Sstas size_t buf_len = 0; 396178825Sdfr gss_buffer_desc mic_buf, mech_buf; 397178825Sdfr gss_buffer_desc mech_output_token; 398178825Sdfr gssspnego_ctx ctx; 399178825Sdfr 400178825Sdfr *minor_status = 0; 401178825Sdfr 402178825Sdfr ctx = (gssspnego_ctx)*context_handle; 403178825Sdfr 404178825Sdfr output_token->length = 0; 405178825Sdfr output_token->value = NULL; 406178825Sdfr 407178825Sdfr mech_output_token.length = 0; 408178825Sdfr mech_output_token.value = NULL; 409178825Sdfr 410178825Sdfr mech_buf.value = NULL; 411178825Sdfr mech_buf.length = 0; 412178825Sdfr 413233294Sstas ret = decode_NegotiationToken(input_token->value, input_token->length, 414233294Sstas &resp, NULL); 415178825Sdfr if (ret) 416233294Sstas return ret; 417178825Sdfr 418233294Sstas if (resp.element != choice_NegotiationToken_negTokenResp) { 419233294Sstas free_NegotiationToken(&resp); 420233294Sstas *minor_status = 0; 421233294Sstas return GSS_S_BAD_MECH; 422178825Sdfr } 423178825Sdfr 424233294Sstas if (resp.u.negTokenResp.negResult == NULL 425233294Sstas || *(resp.u.negTokenResp.negResult) == reject 426233294Sstas /* || resp.u.negTokenResp.supportedMech == NULL */ 427178825Sdfr ) 428178825Sdfr { 429233294Sstas free_NegotiationToken(&resp); 430178825Sdfr return GSS_S_BAD_MECH; 431178825Sdfr } 432178825Sdfr 433178825Sdfr /* 434178825Sdfr * Pick up the mechanism that the acceptor selected, only allow it 435178825Sdfr * to be sent in packet. 436178825Sdfr */ 437178825Sdfr 438178825Sdfr HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 439178825Sdfr 440233294Sstas if (resp.u.negTokenResp.supportedMech) { 441178825Sdfr 442178825Sdfr if (ctx->oidlen) { 443233294Sstas free_NegotiationToken(&resp); 444178825Sdfr HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 445178825Sdfr return GSS_S_BAD_MECH; 446178825Sdfr } 447178825Sdfr ret = der_put_oid(ctx->oidbuf + sizeof(ctx->oidbuf) - 1, 448178825Sdfr sizeof(ctx->oidbuf), 449233294Sstas resp.u.negTokenResp.supportedMech, 450178825Sdfr &ctx->oidlen); 451178825Sdfr /* Avoid recursively embedded SPNEGO */ 452178825Sdfr if (ret || (ctx->oidlen == GSS_SPNEGO_MECHANISM->length && 453178825Sdfr memcmp(ctx->oidbuf + sizeof(ctx->oidbuf) - ctx->oidlen, 454178825Sdfr GSS_SPNEGO_MECHANISM->elements, 455178825Sdfr ctx->oidlen) == 0)) 456178825Sdfr { 457233294Sstas free_NegotiationToken(&resp); 458178825Sdfr HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 459178825Sdfr return GSS_S_BAD_MECH; 460178825Sdfr } 461178825Sdfr 462178825Sdfr /* check if the acceptor took our optimistic token */ 463178825Sdfr if (ctx->oidlen != ctx->preferred_mech_type->length || 464178825Sdfr memcmp(ctx->oidbuf + sizeof(ctx->oidbuf) - ctx->oidlen, 465178825Sdfr ctx->preferred_mech_type->elements, 466178825Sdfr ctx->oidlen) != 0) 467178825Sdfr { 468233294Sstas gss_delete_sec_context(&minor, &ctx->negotiated_ctx_id, 469178825Sdfr GSS_C_NO_BUFFER); 470178825Sdfr ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT; 471178825Sdfr } 472178825Sdfr } else if (ctx->oidlen == 0) { 473233294Sstas free_NegotiationToken(&resp); 474178825Sdfr HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 475178825Sdfr return GSS_S_BAD_MECH; 476178825Sdfr } 477178825Sdfr 478233294Sstas /* if a token (of non zero length), or no context, pass to underlaying mech */ 479233294Sstas if ((resp.u.negTokenResp.responseToken != NULL && resp.u.negTokenResp.responseToken->length) || 480178825Sdfr ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) { 481178825Sdfr gss_buffer_desc mech_input_token; 482178825Sdfr 483233294Sstas if (resp.u.negTokenResp.responseToken) { 484233294Sstas mech_input_token.length = resp.u.negTokenResp.responseToken->length; 485233294Sstas mech_input_token.value = resp.u.negTokenResp.responseToken->data; 486178825Sdfr } else { 487178825Sdfr mech_input_token.length = 0; 488178825Sdfr mech_input_token.value = NULL; 489178825Sdfr } 490178825Sdfr 491178825Sdfr 492178825Sdfr mech.length = ctx->oidlen; 493178825Sdfr mech.elements = ctx->oidbuf + sizeof(ctx->oidbuf) - ctx->oidlen; 494178825Sdfr 495178825Sdfr /* Fall through as if the negotiated mechanism 496178825Sdfr was requested explicitly */ 497178825Sdfr ret = gss_init_sec_context(&minor, 498233294Sstas cred, 499178825Sdfr &ctx->negotiated_ctx_id, 500178825Sdfr ctx->target_name, 501178825Sdfr &mech, 502178825Sdfr req_flags, 503178825Sdfr time_req, 504178825Sdfr input_chan_bindings, 505178825Sdfr &mech_input_token, 506178825Sdfr &ctx->negotiated_mech_type, 507178825Sdfr &mech_output_token, 508178825Sdfr &ctx->mech_flags, 509178825Sdfr &ctx->mech_time_rec); 510178825Sdfr if (GSS_ERROR(ret)) { 511178825Sdfr HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 512233294Sstas free_NegotiationToken(&resp); 513233294Sstas gss_mg_collect_error(&mech, ret, minor); 514178825Sdfr *minor_status = minor; 515178825Sdfr return ret; 516178825Sdfr } 517178825Sdfr if (ret == GSS_S_COMPLETE) { 518178825Sdfr ctx->open = 1; 519178825Sdfr } 520233294Sstas } else if (*(resp.u.negTokenResp.negResult) == accept_completed) { 521178825Sdfr if (ctx->maybe_open) 522178825Sdfr ctx->open = 1; 523178825Sdfr } 524178825Sdfr 525233294Sstas if (*(resp.u.negTokenResp.negResult) == request_mic) { 526178825Sdfr ctx->require_mic = 1; 527178825Sdfr } 528178825Sdfr 529178825Sdfr if (ctx->open) { 530178825Sdfr /* 531178825Sdfr * Verify the mechListMIC if one was provided or CFX was 532178825Sdfr * used and a non-preferred mechanism was selected 533178825Sdfr */ 534233294Sstas if (resp.u.negTokenResp.mechListMIC != NULL) { 535178825Sdfr require_mic = 1; 536178825Sdfr } else { 537178825Sdfr ret = _gss_spnego_require_mechlist_mic(minor_status, ctx, 538178825Sdfr &require_mic); 539178825Sdfr if (ret) { 540178825Sdfr HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 541233294Sstas free_NegotiationToken(&resp); 542178825Sdfr gss_release_buffer(&minor, &mech_output_token); 543178825Sdfr return ret; 544178825Sdfr } 545178825Sdfr } 546178825Sdfr } else { 547178825Sdfr require_mic = 0; 548178825Sdfr } 549178825Sdfr 550178825Sdfr if (require_mic) { 551178825Sdfr ASN1_MALLOC_ENCODE(MechTypeList, mech_buf.value, mech_buf.length, 552178825Sdfr &ctx->initiator_mech_types, &buf_len, ret); 553178825Sdfr if (ret) { 554178825Sdfr HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 555233294Sstas free_NegotiationToken(&resp); 556178825Sdfr gss_release_buffer(&minor, &mech_output_token); 557178825Sdfr *minor_status = ret; 558178825Sdfr return GSS_S_FAILURE; 559178825Sdfr } 560233294Sstas if (mech_buf.length != buf_len) { 561178825Sdfr abort(); 562233294Sstas UNREACHABLE(return GSS_S_FAILURE); 563233294Sstas } 564178825Sdfr 565233294Sstas if (resp.u.negTokenResp.mechListMIC == NULL) { 566178825Sdfr HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 567178825Sdfr free(mech_buf.value); 568233294Sstas free_NegotiationToken(&resp); 569178825Sdfr *minor_status = 0; 570178825Sdfr return GSS_S_DEFECTIVE_TOKEN; 571178825Sdfr } 572233294Sstas mic_buf.length = resp.u.negTokenResp.mechListMIC->length; 573233294Sstas mic_buf.value = resp.u.negTokenResp.mechListMIC->data; 574178825Sdfr 575178825Sdfr if (mech_output_token.length == 0) { 576178825Sdfr ret = gss_verify_mic(minor_status, 577178825Sdfr ctx->negotiated_ctx_id, 578178825Sdfr &mech_buf, 579178825Sdfr &mic_buf, 580178825Sdfr NULL); 581178825Sdfr if (ret) { 582178825Sdfr HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 583178825Sdfr free(mech_buf.value); 584178825Sdfr gss_release_buffer(&minor, &mech_output_token); 585233294Sstas free_NegotiationToken(&resp); 586178825Sdfr return GSS_S_DEFECTIVE_TOKEN; 587178825Sdfr } 588178825Sdfr ctx->verified_mic = 1; 589178825Sdfr } 590178825Sdfr } 591178825Sdfr 592178825Sdfr ret = spnego_reply_internal(minor_status, ctx, 593178825Sdfr require_mic ? &mech_buf : NULL, 594178825Sdfr &mech_output_token, 595178825Sdfr output_token); 596178825Sdfr 597178825Sdfr if (mech_buf.value != NULL) 598178825Sdfr free(mech_buf.value); 599178825Sdfr 600233294Sstas free_NegotiationToken(&resp); 601178825Sdfr gss_release_buffer(&minor, &mech_output_token); 602178825Sdfr 603178825Sdfr if (actual_mech_type) 604178825Sdfr *actual_mech_type = ctx->negotiated_mech_type; 605178825Sdfr if (ret_flags) 606178825Sdfr *ret_flags = ctx->mech_flags; 607178825Sdfr if (time_rec) 608178825Sdfr *time_rec = ctx->mech_time_rec; 609178825Sdfr 610178825Sdfr HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 611178825Sdfr return ret; 612178825Sdfr} 613178825Sdfr 614233294SstasOM_uint32 GSSAPI_CALLCONV 615233294Sstas_gss_spnego_init_sec_context 616178825Sdfr (OM_uint32 * minor_status, 617178825Sdfr const gss_cred_id_t initiator_cred_handle, 618178825Sdfr gss_ctx_id_t * context_handle, 619178825Sdfr const gss_name_t target_name, 620178825Sdfr const gss_OID mech_type, 621178825Sdfr OM_uint32 req_flags, 622178825Sdfr OM_uint32 time_req, 623178825Sdfr const gss_channel_bindings_t input_chan_bindings, 624178825Sdfr const gss_buffer_t input_token, 625178825Sdfr gss_OID * actual_mech_type, 626178825Sdfr gss_buffer_t output_token, 627178825Sdfr OM_uint32 * ret_flags, 628178825Sdfr OM_uint32 * time_rec 629178825Sdfr ) 630178825Sdfr{ 631178825Sdfr if (*context_handle == GSS_C_NO_CONTEXT) 632178825Sdfr return spnego_initial (minor_status, 633233294Sstas initiator_cred_handle, 634178825Sdfr context_handle, 635178825Sdfr target_name, 636178825Sdfr mech_type, 637178825Sdfr req_flags, 638178825Sdfr time_req, 639178825Sdfr input_chan_bindings, 640178825Sdfr input_token, 641178825Sdfr actual_mech_type, 642178825Sdfr output_token, 643178825Sdfr ret_flags, 644178825Sdfr time_rec); 645178825Sdfr else 646178825Sdfr return spnego_reply (minor_status, 647233294Sstas initiator_cred_handle, 648178825Sdfr context_handle, 649178825Sdfr target_name, 650178825Sdfr mech_type, 651178825Sdfr req_flags, 652178825Sdfr time_req, 653178825Sdfr input_chan_bindings, 654178825Sdfr input_token, 655178825Sdfr actual_mech_type, 656178825Sdfr output_token, 657178825Sdfr ret_flags, 658178825Sdfr time_rec); 659178825Sdfr} 660178825Sdfr 661