root/source4/heimdal/lib/gssapi/spnego/init_sec_context.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. initiator_approved
  2. spnego_reply_internal

   1 /*
   2  * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
   3  * (Royal Institute of Technology, Stockholm, Sweden).
   4  * Portions Copyright (c) 2004 PADL Software Pty Ltd.
   5  *
   6  * Redistribution and use in source and binary forms, with or without
   7  * modification, are permitted provided that the following conditions
   8  * are met:
   9  *
  10  * 1. Redistributions of source code must retain the above copyright
  11  *    notice, this list of conditions and the following disclaimer.
  12  *
  13  * 2. Redistributions in binary form must reproduce the above copyright
  14  *    notice, this list of conditions and the following disclaimer in the
  15  *    documentation and/or other materials provided with the distribution.
  16  *
  17  * 3. Neither the name of the Institute nor the names of its contributors
  18  *    may be used to endorse or promote products derived from this software
  19  *    without specific prior written permission.
  20  *
  21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31  * SUCH DAMAGE.
  32  */
  33 
  34 #include "spnego/spnego_locl.h"
  35 
  36 RCSID("$Id$");
  37 
  38 /*
  39  * Is target_name an sane target for `mech´.
  40  */
  41 
  42 static OM_uint32
  43 initiator_approved(gss_name_t target_name, gss_OID mech)
     /* [<][>][^][v][top][bottom][index][help] */
  44 {
  45     OM_uint32 min_stat, maj_stat;
  46     gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
  47     gss_buffer_desc out;
  48 
  49     maj_stat = gss_init_sec_context(&min_stat,
  50                                     GSS_C_NO_CREDENTIAL,
  51                                     &ctx,
  52                                     target_name,
  53                                     mech,
  54                                     0,
  55                                     GSS_C_INDEFINITE,
  56                                     GSS_C_NO_CHANNEL_BINDINGS,
  57                                     GSS_C_NO_BUFFER,
  58                                     NULL,
  59                                     &out,
  60                                     NULL,
  61                                     NULL);
  62     if (GSS_ERROR(maj_stat)) {
  63         gss_mg_collect_error(mech, maj_stat, min_stat);
  64         return GSS_S_BAD_MECH;
  65     }
  66     gss_release_buffer(&min_stat, &out);
  67     gss_delete_sec_context(&min_stat, &ctx, NULL);
  68 
  69     return GSS_S_COMPLETE;
  70 }
  71 
  72 /*
  73  * Send a reply. Note that we only need to send a reply if we
  74  * need to send a MIC or a mechanism token. Otherwise, we can
  75  * return an empty buffer.
  76  *
  77  * The return value of this will be returned to the API, so it
  78  * must return GSS_S_CONTINUE_NEEDED if a token was generated.
  79  */
  80 static OM_uint32
  81 spnego_reply_internal(OM_uint32 *minor_status,
     /* [<][>][^][v][top][bottom][index][help] */
  82                       gssspnego_ctx context_handle,
  83                       const gss_buffer_t mech_buf,
  84                       gss_buffer_t mech_token,
  85                       gss_buffer_t output_token)
  86 {
  87     NegotiationToken nt;
  88     gss_buffer_desc mic_buf;
  89     OM_uint32 ret;
  90     size_t size;
  91 
  92     if (mech_buf == GSS_C_NO_BUFFER && mech_token->length == 0) {
  93         output_token->length = 0;
  94         output_token->value = NULL;
  95 
  96         return context_handle->open ? GSS_S_COMPLETE : GSS_S_FAILURE;
  97     }
  98 
  99     memset(&nt, 0, sizeof(nt));
 100 
 101     nt.element = choice_NegotiationToken_negTokenResp;
 102 
 103     ALLOC(nt.u.negTokenResp.negResult, 1);
 104     if (nt.u.negTokenResp.negResult == NULL) {
 105         *minor_status = ENOMEM;
 106         return GSS_S_FAILURE;
 107     }
 108 
 109     nt.u.negTokenResp.supportedMech = NULL;
 110 
 111     output_token->length = 0;
 112     output_token->value = NULL;
 113 
 114     if (mech_token->length == 0) {
 115         nt.u.negTokenResp.responseToken = NULL;
 116         *(nt.u.negTokenResp.negResult)  = accept_completed;
 117     } else {
 118         ALLOC(nt.u.negTokenResp.responseToken, 1);
 119         if (nt.u.negTokenResp.responseToken == NULL) {
 120             free_NegotiationToken(&nt);
 121             *minor_status = ENOMEM;
 122             return GSS_S_FAILURE;
 123         }
 124         nt.u.negTokenResp.responseToken->length = mech_token->length;
 125         nt.u.negTokenResp.responseToken->data   = mech_token->value;
 126         mech_token->length = 0;
 127         mech_token->value  = NULL;
 128 
 129         *(nt.u.negTokenResp.negResult)  = accept_incomplete;
 130     }
 131 
 132     if (mech_buf != GSS_C_NO_BUFFER) {
 133 
 134         ret = gss_get_mic(minor_status,
 135                           context_handle->negotiated_ctx_id,
 136                           0,
 137                           mech_buf,
 138                           &mic_buf);
 139         if (ret == GSS_S_COMPLETE) {
 140             ALLOC(nt.u.negTokenResp.mechListMIC, 1);
 141             if (nt.u.negTokenResp.mechListMIC == NULL) {
 142                 gss_release_buffer(minor_status, &mic_buf);
 143                 free_NegotiationToken(&nt);
 144                 *minor_status = ENOMEM;
 145                 return GSS_S_FAILURE;
 146             }
 147 
 148             nt.u.negTokenResp.mechListMIC->length = mic_buf.length;
 149             nt.u.negTokenResp.mechListMIC->data   = mic_buf.value;
 150         } else if (ret == GSS_S_UNAVAILABLE) {
 151             nt.u.negTokenResp.mechListMIC = NULL;
 152         } if (ret) {
 153             free_NegotiationToken(&nt);
 154             *minor_status = ENOMEM;
 155             return GSS_S_FAILURE;
 156         }
 157     } else {
 158         nt.u.negTokenResp.mechListMIC = NULL;
 159     }
 160 
 161     ASN1_MALLOC_ENCODE(NegotiationToken,
 162                        output_token->value, output_token->length,
 163                        &nt, &size, ret);
 164     if (ret) {
 165         free_NegotiationToken(&nt);
 166         *minor_status = ret;
 167         return GSS_S_FAILURE;
 168     }
 169 
 170     if (*(nt.u.negTokenResp.negResult) == accept_completed)
 171         ret = GSS_S_COMPLETE;
 172     else
 173         ret = GSS_S_CONTINUE_NEEDED;
 174 
 175     free_NegotiationToken(&nt);
 176     return ret;
 177 }
 178 
 179 static OM_uint32
 180 spnego_initial
 181            (OM_uint32 * minor_status,
 182             gssspnego_cred cred,
 183             gss_ctx_id_t * context_handle,
 184             const gss_name_t target_name,
 185             const gss_OID mech_type,
 186             OM_uint32 req_flags,
 187             OM_uint32 time_req,
 188             const gss_channel_bindings_t input_chan_bindings,
 189             const gss_buffer_t input_token,
 190             gss_OID * actual_mech_type,
 191             gss_buffer_t output_token,
 192             OM_uint32 * ret_flags,
 193             OM_uint32 * time_rec
 194     )
 195 {
 196     NegTokenInit ni;
 197     int ret;
 198     OM_uint32 sub, minor;
 199     gss_buffer_desc mech_token;
 200     u_char *buf;
 201     size_t buf_size, buf_len;
 202     gss_buffer_desc data;
 203     size_t ni_len;
 204     gss_ctx_id_t context;
 205     gssspnego_ctx ctx;
 206     spnego_name name = (spnego_name)target_name;
 207 
 208     *minor_status = 0;
 209 
 210     memset (&ni, 0, sizeof(ni));
 211 
 212     *context_handle = GSS_C_NO_CONTEXT;
 213 
 214     if (target_name == GSS_C_NO_NAME)
 215         return GSS_S_BAD_NAME;
 216 
 217     sub = _gss_spnego_alloc_sec_context(&minor, &context);
 218     if (GSS_ERROR(sub)) {
 219         *minor_status = minor;
 220         return sub;
 221     }
 222     ctx = (gssspnego_ctx)context;
 223 
 224     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
 225 
 226     ctx->local = 1;
 227 
 228     sub = gss_import_name(&minor, &name->value, &name->type, &ctx->target_name);
 229     if (GSS_ERROR(sub)) {
 230         *minor_status = minor;
 231         _gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER);
 232         return sub;
 233     }
 234 
 235     sub = _gss_spnego_indicate_mechtypelist(&minor,
 236                                             ctx->target_name,
 237                                             initiator_approved,
 238                                             0,
 239                                             cred,
 240                                             &ni.mechTypes,
 241                                             &ctx->preferred_mech_type);
 242     if (GSS_ERROR(sub)) {
 243         *minor_status = minor;
 244         _gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER);
 245         return sub;
 246     }
 247 
 248     ni.reqFlags = NULL;
 249 
 250     /*
 251      * If we have a credential handle, use it to select the mechanism
 252      * that we will use
 253      */
 254 
 255     /* generate optimistic token */
 256     sub = gss_init_sec_context(&minor,
 257                                (cred != NULL) ? cred->negotiated_cred_id :
 258                                   GSS_C_NO_CREDENTIAL,
 259                                &ctx->negotiated_ctx_id,
 260                                ctx->target_name,
 261                                ctx->preferred_mech_type,
 262                                req_flags,
 263                                time_req,
 264                                input_chan_bindings,
 265                                input_token,
 266                                &ctx->negotiated_mech_type,
 267                                &mech_token,
 268                                &ctx->mech_flags,
 269                                &ctx->mech_time_rec);
 270     if (GSS_ERROR(sub)) {
 271         free_NegTokenInit(&ni);
 272         *minor_status = minor;
 273         gss_mg_collect_error(ctx->preferred_mech_type, sub, minor);
 274         _gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER);
 275         return sub;
 276     }
 277     if (sub == GSS_S_COMPLETE)
 278         ctx->maybe_open = 1;
 279 
 280     if (mech_token.length != 0) {
 281         ALLOC(ni.mechToken, 1);
 282         if (ni.mechToken == NULL) {
 283             free_NegTokenInit(&ni);
 284             gss_release_buffer(&minor, &mech_token);
 285             _gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER);
 286             *minor_status = ENOMEM;
 287             return GSS_S_FAILURE;
 288         }
 289         ni.mechToken->length = mech_token.length;
 290         ni.mechToken->data = malloc(mech_token.length);
 291         if (ni.mechToken->data == NULL && mech_token.length != 0) {
 292             free_NegTokenInit(&ni);
 293             gss_release_buffer(&minor, &mech_token);
 294             *minor_status = ENOMEM;
 295             _gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER);
 296             return GSS_S_FAILURE;
 297         }
 298         memcpy(ni.mechToken->data, mech_token.value, mech_token.length);
 299         gss_release_buffer(&minor, &mech_token);
 300     } else
 301         ni.mechToken = NULL;
 302 
 303     ni.mechListMIC = NULL;
 304 
 305     ni_len = length_NegTokenInit(&ni);
 306     buf_size = 1 + der_length_len(ni_len) + ni_len;
 307 
 308     buf = malloc(buf_size);
 309     if (buf == NULL) {
 310         free_NegTokenInit(&ni);
 311         *minor_status = ENOMEM;
 312         _gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER);
 313         return GSS_S_FAILURE;
 314     }
 315 
 316     ret = encode_NegTokenInit(buf + buf_size - 1,
 317                               ni_len,
 318                               &ni, &buf_len);
 319     if (ret == 0 && ni_len != buf_len)
 320         abort();
 321 
 322     if (ret == 0) {
 323         size_t tmp;
 324 
 325         ret = der_put_length_and_tag(buf + buf_size - buf_len - 1,
 326                                      buf_size - buf_len,
 327                                      buf_len,
 328                                      ASN1_C_CONTEXT,
 329                                      CONS,
 330                                      0,
 331                                      &tmp);
 332         if (ret == 0 && tmp + buf_len != buf_size)
 333             abort();
 334     }
 335     if (ret) {
 336         *minor_status = ret;
 337         free(buf);
 338         free_NegTokenInit(&ni);
 339         _gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER);
 340         return GSS_S_FAILURE;
 341     }
 342 
 343     data.value  = buf;
 344     data.length = buf_size;
 345 
 346     ctx->initiator_mech_types.len = ni.mechTypes.len;
 347     ctx->initiator_mech_types.val = ni.mechTypes.val;
 348     ni.mechTypes.len = 0;
 349     ni.mechTypes.val = NULL;
 350 
 351     free_NegTokenInit(&ni);
 352 
 353     sub = gss_encapsulate_token(&data,
 354                                 GSS_SPNEGO_MECHANISM,
 355                                 output_token);
 356     free (buf);
 357 
 358     if (sub) {
 359         _gss_spnego_internal_delete_sec_context(&minor, &context, GSS_C_NO_BUFFER);
 360         return sub;
 361     }
 362 
 363     if (actual_mech_type)
 364         *actual_mech_type = ctx->negotiated_mech_type;
 365     if (ret_flags)
 366         *ret_flags = ctx->mech_flags;
 367     if (time_rec)
 368         *time_rec = ctx->mech_time_rec;
 369 
 370     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 371 
 372     *context_handle = context;
 373 
 374     return GSS_S_CONTINUE_NEEDED;
 375 }
 376 
 377 static OM_uint32
 378 spnego_reply
 379            (OM_uint32 * minor_status,
 380             const gssspnego_cred cred,
 381             gss_ctx_id_t * context_handle,
 382             const gss_name_t target_name,
 383             const gss_OID mech_type,
 384             OM_uint32 req_flags,
 385             OM_uint32 time_req,
 386             const gss_channel_bindings_t input_chan_bindings,
 387             const gss_buffer_t input_token,
 388             gss_OID * actual_mech_type,
 389             gss_buffer_t output_token,
 390             OM_uint32 * ret_flags,
 391             OM_uint32 * time_rec
 392     )
 393 {
 394     OM_uint32 ret, minor;
 395     NegTokenResp resp;
 396     size_t len, taglen;
 397     gss_OID_desc mech;
 398     int require_mic;
 399     size_t buf_len;
 400     gss_buffer_desc mic_buf, mech_buf;
 401     gss_buffer_desc mech_output_token;
 402     gssspnego_ctx ctx;
 403 
 404     *minor_status = 0;
 405 
 406     ctx = (gssspnego_ctx)*context_handle;
 407 
 408     output_token->length = 0;
 409     output_token->value  = NULL;
 410 
 411     mech_output_token.length = 0;
 412     mech_output_token.value = NULL;
 413 
 414     mech_buf.value = NULL;
 415     mech_buf.length = 0;
 416 
 417     ret = der_match_tag_and_length(input_token->value, input_token->length,
 418                                    ASN1_C_CONTEXT, CONS, 1, &len, &taglen);
 419     if (ret)
 420         return ret;
 421 
 422     if (len > input_token->length - taglen)
 423         return ASN1_OVERRUN;
 424 
 425     ret = decode_NegTokenResp((const unsigned char *)input_token->value+taglen,
 426                               len, &resp, NULL);
 427     if (ret) {
 428         *minor_status = ENOMEM;
 429         return GSS_S_FAILURE;
 430     }
 431 
 432     if (resp.negResult == NULL
 433         || *(resp.negResult) == reject
 434         /* || resp.supportedMech == NULL */
 435         )
 436     {
 437         free_NegTokenResp(&resp);
 438         return GSS_S_BAD_MECH;
 439     }
 440 
 441     /*
 442      * Pick up the mechanism that the acceptor selected, only allow it
 443      * to be sent in packet.
 444      */
 445 
 446     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
 447 
 448     if (resp.supportedMech) {
 449 
 450         if (ctx->oidlen) {
 451             free_NegTokenResp(&resp);
 452             HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 453             return GSS_S_BAD_MECH;
 454         }
 455         ret = der_put_oid(ctx->oidbuf + sizeof(ctx->oidbuf) - 1,
 456                           sizeof(ctx->oidbuf),
 457                           resp.supportedMech,
 458                           &ctx->oidlen);
 459         /* Avoid recursively embedded SPNEGO */
 460         if (ret || (ctx->oidlen == GSS_SPNEGO_MECHANISM->length &&
 461                     memcmp(ctx->oidbuf + sizeof(ctx->oidbuf) - ctx->oidlen,
 462                            GSS_SPNEGO_MECHANISM->elements,
 463                            ctx->oidlen) == 0))
 464         {
 465             free_NegTokenResp(&resp);
 466             HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 467             return GSS_S_BAD_MECH;
 468         }
 469 
 470         /* check if the acceptor took our optimistic token */
 471         if (ctx->oidlen != ctx->preferred_mech_type->length ||
 472             memcmp(ctx->oidbuf + sizeof(ctx->oidbuf) - ctx->oidlen,
 473                    ctx->preferred_mech_type->elements,
 474                    ctx->oidlen) != 0)
 475         {
 476             gss_delete_sec_context(&minor, &ctx->negotiated_ctx_id,
 477                                    GSS_C_NO_BUFFER);
 478             ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;
 479         }
 480     } else if (ctx->oidlen == 0) {
 481         free_NegTokenResp(&resp);
 482         HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 483         return GSS_S_BAD_MECH;
 484     }
 485 
 486     /* if a token (of non zero length), or no context, pass to underlaying mech */
 487     if ((resp.responseToken != NULL && resp.responseToken->length) ||
 488         ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
 489         gss_buffer_desc mech_input_token;
 490 
 491         if (resp.responseToken) {
 492             mech_input_token.length = resp.responseToken->length;
 493             mech_input_token.value  = resp.responseToken->data;
 494         } else {
 495             mech_input_token.length = 0;
 496             mech_input_token.value = NULL;
 497         }
 498 
 499 
 500         mech.length = ctx->oidlen;
 501         mech.elements = ctx->oidbuf + sizeof(ctx->oidbuf) - ctx->oidlen;
 502 
 503         /* Fall through as if the negotiated mechanism
 504            was requested explicitly */
 505         ret = gss_init_sec_context(&minor,
 506                                    (cred != NULL) ? cred->negotiated_cred_id :
 507                                        GSS_C_NO_CREDENTIAL,
 508                                    &ctx->negotiated_ctx_id,
 509                                    ctx->target_name,
 510                                    &mech,
 511                                    req_flags,
 512                                    time_req,
 513                                    input_chan_bindings,
 514                                    &mech_input_token,
 515                                    &ctx->negotiated_mech_type,
 516                                    &mech_output_token,
 517                                    &ctx->mech_flags,
 518                                    &ctx->mech_time_rec);
 519         if (GSS_ERROR(ret)) {
 520             HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 521             free_NegTokenResp(&resp);
 522             gss_mg_collect_error(&mech, ret, minor);
 523             *minor_status = minor;
 524             return ret;
 525         }
 526         if (ret == GSS_S_COMPLETE) {
 527             ctx->open = 1;
 528         }
 529     } else if (*(resp.negResult) == accept_completed) {
 530         if (ctx->maybe_open)
 531             ctx->open = 1;
 532     }
 533 
 534     if (*(resp.negResult) == request_mic) {
 535         ctx->require_mic = 1;
 536     }
 537 
 538     if (ctx->open) {
 539         /*
 540          * Verify the mechListMIC if one was provided or CFX was
 541          * used and a non-preferred mechanism was selected
 542          */
 543         if (resp.mechListMIC != NULL) {
 544             require_mic = 1;
 545         } else {
 546             ret = _gss_spnego_require_mechlist_mic(minor_status, ctx,
 547                                                    &require_mic);
 548             if (ret) {
 549                 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 550                 free_NegTokenResp(&resp);
 551                 gss_release_buffer(&minor, &mech_output_token);
 552                 return ret;
 553             }
 554         }
 555     } else {
 556         require_mic = 0;
 557     }
 558 
 559     if (require_mic) {
 560         ASN1_MALLOC_ENCODE(MechTypeList, mech_buf.value, mech_buf.length,
 561                            &ctx->initiator_mech_types, &buf_len, ret);
 562         if (ret) {
 563             HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 564             free_NegTokenResp(&resp);
 565             gss_release_buffer(&minor, &mech_output_token);
 566             *minor_status = ret;
 567             return GSS_S_FAILURE;
 568         }
 569         if (mech_buf.length != buf_len)
 570             abort();
 571 
 572         if (resp.mechListMIC == NULL) {
 573             HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 574             free(mech_buf.value);
 575             free_NegTokenResp(&resp);
 576             *minor_status = 0;
 577             return GSS_S_DEFECTIVE_TOKEN;
 578         }
 579         mic_buf.length = resp.mechListMIC->length;
 580         mic_buf.value  = resp.mechListMIC->data;
 581 
 582         if (mech_output_token.length == 0) {
 583             ret = gss_verify_mic(minor_status,
 584                                  ctx->negotiated_ctx_id,
 585                                  &mech_buf,
 586                                  &mic_buf,
 587                                  NULL);
 588            if (ret) {
 589                 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 590                 free(mech_buf.value);
 591                 gss_release_buffer(&minor, &mech_output_token);
 592                 free_NegTokenResp(&resp);
 593                 return GSS_S_DEFECTIVE_TOKEN;
 594             }
 595             ctx->verified_mic = 1;
 596         }
 597     }
 598 
 599     ret = spnego_reply_internal(minor_status, ctx,
 600                                 require_mic ? &mech_buf : NULL,
 601                                 &mech_output_token,
 602                                 output_token);
 603 
 604     if (mech_buf.value != NULL)
 605         free(mech_buf.value);
 606 
 607     free_NegTokenResp(&resp);
 608     gss_release_buffer(&minor, &mech_output_token);
 609 
 610     if (actual_mech_type)
 611         *actual_mech_type = ctx->negotiated_mech_type;
 612     if (ret_flags)
 613         *ret_flags = ctx->mech_flags;
 614     if (time_rec)
 615         *time_rec = ctx->mech_time_rec;
 616 
 617     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 618     return ret;
 619 }
 620 
 621 OM_uint32 _gss_spnego_init_sec_context
 622            (OM_uint32 * minor_status,
 623             const gss_cred_id_t initiator_cred_handle,
 624             gss_ctx_id_t * context_handle,
 625             const gss_name_t target_name,
 626             const gss_OID mech_type,
 627             OM_uint32 req_flags,
 628             OM_uint32 time_req,
 629             const gss_channel_bindings_t input_chan_bindings,
 630             const gss_buffer_t input_token,
 631             gss_OID * actual_mech_type,
 632             gss_buffer_t output_token,
 633             OM_uint32 * ret_flags,
 634             OM_uint32 * time_rec
 635            )
 636 {
 637     gssspnego_cred cred = (gssspnego_cred)initiator_cred_handle;
 638 
 639     if (*context_handle == GSS_C_NO_CONTEXT)
 640         return spnego_initial (minor_status,
 641                                cred,
 642                                context_handle,
 643                                target_name,
 644                                mech_type,
 645                                req_flags,
 646                                time_req,
 647                                input_chan_bindings,
 648                                input_token,
 649                                actual_mech_type,
 650                                output_token,
 651                                ret_flags,
 652                                time_rec);
 653     else
 654         return spnego_reply (minor_status,
 655                              cred,
 656                              context_handle,
 657                              target_name,
 658                              mech_type,
 659                              req_flags,
 660                              time_req,
 661                              input_chan_bindings,
 662                              input_token,
 663                              actual_mech_type,
 664                              output_token,
 665                              ret_flags,
 666                              time_rec);
 667 }
 668 

/* [<][>][^][v][top][bottom][index][help] */