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

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

DEFINITIONS

This source file includes following definitions.
  1. send_reject
  2. acceptor_approved
  3. send_supported_mechs
  4. send_accept
  5. select_mech
  6. acceptor_complete

   1 /*
   2  * Copyright (c) 1997 - 2006 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 static OM_uint32
  39 send_reject (OM_uint32 *minor_status,
     /* [<][>][^][v][top][bottom][index][help] */
  40              gss_buffer_t output_token)
  41 {
  42     NegotiationToken nt;
  43     size_t size;
  44 
  45     nt.element = choice_NegotiationToken_negTokenResp;
  46 
  47     ALLOC(nt.u.negTokenResp.negResult, 1);
  48     if (nt.u.negTokenResp.negResult == NULL) {
  49         *minor_status = ENOMEM;
  50         return GSS_S_FAILURE;
  51     }
  52     *(nt.u.negTokenResp.negResult)  = reject;
  53     nt.u.negTokenResp.supportedMech = NULL;
  54     nt.u.negTokenResp.responseToken = NULL;
  55     nt.u.negTokenResp.mechListMIC   = NULL;
  56 
  57     ASN1_MALLOC_ENCODE(NegotiationToken,
  58                        output_token->value, output_token->length, &nt,
  59                        &size, *minor_status);
  60     free_NegotiationToken(&nt);
  61     if (*minor_status != 0)
  62         return GSS_S_FAILURE;
  63 
  64     return GSS_S_BAD_MECH;
  65 }
  66 
  67 static OM_uint32
  68 acceptor_approved(gss_name_t target_name, gss_OID mech)
     /* [<][>][^][v][top][bottom][index][help] */
  69 {
  70     gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
  71     gss_OID_set oidset;
  72     OM_uint32 junk, ret;
  73 
  74     if (target_name == GSS_C_NO_NAME)
  75         return GSS_S_COMPLETE;
  76 
  77     gss_create_empty_oid_set(&junk, &oidset);
  78     gss_add_oid_set_member(&junk, mech, &oidset);
  79 
  80     ret = gss_acquire_cred(&junk, target_name, GSS_C_INDEFINITE, oidset,
  81                            GSS_C_ACCEPT, &cred, NULL, NULL);
  82     gss_release_oid_set(&junk, &oidset);
  83     if (ret != GSS_S_COMPLETE)
  84         return ret;
  85     gss_release_cred(&junk, &cred);
  86 
  87     return GSS_S_COMPLETE;
  88 }
  89 
  90 static OM_uint32
  91 send_supported_mechs (OM_uint32 *minor_status,
     /* [<][>][^][v][top][bottom][index][help] */
  92                       gss_buffer_t output_token)
  93 {
  94     NegotiationTokenWin nt;
  95     char hostname[MAXHOSTNAMELEN + 1], *p;
  96     gss_buffer_desc name_buf;
  97     gss_OID name_type;
  98     gss_name_t target_princ;
  99     gss_name_t canon_princ;
 100     OM_uint32 minor;
 101     size_t buf_len;
 102     gss_buffer_desc data;
 103     OM_uint32 ret;
 104 
 105     memset(&nt, 0, sizeof(nt));
 106 
 107     nt.element = choice_NegotiationTokenWin_negTokenInit;
 108     nt.u.negTokenInit.reqFlags = NULL;
 109     nt.u.negTokenInit.mechToken = NULL;
 110     nt.u.negTokenInit.negHints = NULL;
 111 
 112     ret = _gss_spnego_indicate_mechtypelist(minor_status, GSS_C_NO_NAME,
 113                                             acceptor_approved, 1, NULL,
 114                                             &nt.u.negTokenInit.mechTypes, NULL);
 115     if (ret != GSS_S_COMPLETE) {
 116         return ret;
 117     }
 118 
 119     memset(&target_princ, 0, sizeof(target_princ));
 120     if (gethostname(hostname, sizeof(hostname) - 2) != 0) {
 121         *minor_status = errno;
 122         free_NegotiationTokenWin(&nt);
 123         return GSS_S_FAILURE;
 124     }
 125     hostname[sizeof(hostname) - 1] = '\0';
 126 
 127     /* Send the constructed SAM name for this host */
 128     for (p = hostname; *p != '\0' && *p != '.'; p++) {
 129         *p = toupper((unsigned char)*p);
 130     }
 131     *p++ = '$';
 132     *p = '\0';
 133 
 134     name_buf.length = strlen(hostname);
 135     name_buf.value = hostname;
 136 
 137     ret = gss_import_name(minor_status, &name_buf,
 138                           GSS_C_NO_OID,
 139                           &target_princ);
 140     if (ret != GSS_S_COMPLETE) {
 141         free_NegotiationTokenWin(&nt);
 142         return ret;
 143     }
 144 
 145     name_buf.length = 0;
 146     name_buf.value = NULL;
 147 
 148     /* Canonicalize the name using the preferred mechanism */
 149     ret = gss_canonicalize_name(minor_status,
 150                                 target_princ,
 151                                 GSS_C_NO_OID,
 152                                 &canon_princ);
 153     if (ret != GSS_S_COMPLETE) {
 154         free_NegotiationTokenWin(&nt);
 155         gss_release_name(&minor, &target_princ);
 156         return ret;
 157     }
 158 
 159     ret = gss_display_name(minor_status, canon_princ,
 160                            &name_buf, &name_type);
 161     if (ret != GSS_S_COMPLETE) {
 162         free_NegotiationTokenWin(&nt);
 163         gss_release_name(&minor, &canon_princ);
 164         gss_release_name(&minor, &target_princ);
 165         return ret;
 166     }
 167 
 168     gss_release_name(&minor, &canon_princ);
 169     gss_release_name(&minor, &target_princ);
 170 
 171     ALLOC(nt.u.negTokenInit.negHints, 1);
 172     if (nt.u.negTokenInit.negHints == NULL) {
 173         *minor_status = ENOMEM;
 174         gss_release_buffer(&minor, &name_buf);
 175         free_NegotiationTokenWin(&nt);
 176         return GSS_S_FAILURE;
 177     }
 178 
 179     ALLOC(nt.u.negTokenInit.negHints->hintName, 1);
 180     if (nt.u.negTokenInit.negHints->hintName == NULL) {
 181         *minor_status = ENOMEM;
 182         gss_release_buffer(&minor, &name_buf);
 183         free_NegotiationTokenWin(&nt);
 184         return GSS_S_FAILURE;
 185     }
 186 
 187     *(nt.u.negTokenInit.negHints->hintName) = name_buf.value;
 188     name_buf.value = NULL;
 189     nt.u.negTokenInit.negHints->hintAddress = NULL;
 190 
 191     ASN1_MALLOC_ENCODE(NegotiationTokenWin,
 192                        data.value, data.length, &nt, &buf_len, ret);
 193     free_NegotiationTokenWin(&nt);
 194     if (ret) {
 195         return ret;
 196     }
 197     if (data.length != buf_len)
 198         abort();
 199 
 200     ret = gss_encapsulate_token(&data, GSS_SPNEGO_MECHANISM, output_token);
 201 
 202     free (data.value);
 203 
 204     if (ret != GSS_S_COMPLETE)
 205         return ret;
 206 
 207     *minor_status = 0;
 208 
 209     return GSS_S_CONTINUE_NEEDED;
 210 }
 211 
 212 static OM_uint32
 213 send_accept (OM_uint32 *minor_status,
     /* [<][>][^][v][top][bottom][index][help] */
 214              gssspnego_ctx context_handle,
 215              gss_buffer_t mech_token,
 216              int initial_response,
 217              gss_buffer_t mech_buf,
 218              gss_buffer_t output_token)
 219 {
 220     NegotiationToken nt;
 221     OM_uint32 ret;
 222     gss_buffer_desc mech_mic_buf;
 223     size_t size;
 224 
 225     memset(&nt, 0, sizeof(nt));
 226 
 227     nt.element = choice_NegotiationToken_negTokenResp;
 228 
 229     ALLOC(nt.u.negTokenResp.negResult, 1);
 230     if (nt.u.negTokenResp.negResult == NULL) {
 231         *minor_status = ENOMEM;
 232         return GSS_S_FAILURE;
 233     }
 234 
 235     if (context_handle->open) {
 236         if (mech_token != GSS_C_NO_BUFFER
 237             && mech_token->length != 0
 238             && mech_buf != GSS_C_NO_BUFFER)
 239             *(nt.u.negTokenResp.negResult)  = accept_incomplete;
 240         else
 241             *(nt.u.negTokenResp.negResult)  = accept_completed;
 242     } else {
 243         if (initial_response && context_handle->require_mic)
 244             *(nt.u.negTokenResp.negResult)  = request_mic;
 245         else
 246             *(nt.u.negTokenResp.negResult)  = accept_incomplete;
 247     }
 248 
 249     if (initial_response) {
 250         ALLOC(nt.u.negTokenResp.supportedMech, 1);
 251         if (nt.u.negTokenResp.supportedMech == NULL) {
 252             free_NegotiationToken(&nt);
 253             *minor_status = ENOMEM;
 254             return GSS_S_FAILURE;
 255         }
 256 
 257         ret = der_get_oid(context_handle->preferred_mech_type->elements,
 258                           context_handle->preferred_mech_type->length,
 259                           nt.u.negTokenResp.supportedMech,
 260                           NULL);
 261         if (ret) {
 262             free_NegotiationToken(&nt);
 263             *minor_status = ENOMEM;
 264             return GSS_S_FAILURE;
 265         }
 266     } else {
 267         nt.u.negTokenResp.supportedMech = NULL;
 268     }
 269 
 270     if (mech_token != GSS_C_NO_BUFFER && mech_token->length != 0) {
 271         ALLOC(nt.u.negTokenResp.responseToken, 1);
 272         if (nt.u.negTokenResp.responseToken == NULL) {
 273             free_NegotiationToken(&nt);
 274             *minor_status = ENOMEM;
 275             return GSS_S_FAILURE;
 276         }
 277         nt.u.negTokenResp.responseToken->length = mech_token->length;
 278         nt.u.negTokenResp.responseToken->data   = mech_token->value;
 279         mech_token->length = 0;
 280         mech_token->value  = NULL;
 281     } else {
 282         nt.u.negTokenResp.responseToken = NULL;
 283     }
 284 
 285     if (mech_buf != GSS_C_NO_BUFFER) {
 286         ret = gss_get_mic(minor_status,
 287                           context_handle->negotiated_ctx_id,
 288                           0,
 289                           mech_buf,
 290                           &mech_mic_buf);
 291         if (ret == GSS_S_COMPLETE) {
 292             ALLOC(nt.u.negTokenResp.mechListMIC, 1);
 293             if (nt.u.negTokenResp.mechListMIC == NULL) {
 294                 gss_release_buffer(minor_status, &mech_mic_buf);
 295                 free_NegotiationToken(&nt);
 296                 *minor_status = ENOMEM;
 297                 return GSS_S_FAILURE;
 298             }
 299             nt.u.negTokenResp.mechListMIC->length = mech_mic_buf.length;
 300             nt.u.negTokenResp.mechListMIC->data   = mech_mic_buf.value;
 301         } else if (ret == GSS_S_UNAVAILABLE) {
 302             nt.u.negTokenResp.mechListMIC = NULL;
 303         } else {
 304             free_NegotiationToken(&nt);
 305             return ret;
 306         }
 307 
 308     } else
 309         nt.u.negTokenResp.mechListMIC = NULL;
 310 
 311     ASN1_MALLOC_ENCODE(NegotiationToken,
 312                        output_token->value, output_token->length,
 313                        &nt, &size, ret);
 314     if (ret) {
 315         free_NegotiationToken(&nt);
 316         *minor_status = ret;
 317         return GSS_S_FAILURE;
 318     }
 319 
 320     /*
 321      * The response should not be encapsulated, because
 322      * it is a SubsequentContextToken (note though RFC 1964
 323      * specifies encapsulation for all _Kerberos_ tokens).
 324      */
 325 
 326     if (*(nt.u.negTokenResp.negResult) == accept_completed)
 327         ret = GSS_S_COMPLETE;
 328     else
 329         ret = GSS_S_CONTINUE_NEEDED;
 330     free_NegotiationToken(&nt);
 331     return ret;
 332 }
 333 
 334 
 335 static OM_uint32
 336 verify_mechlist_mic
 337            (OM_uint32 *minor_status,
 338             gssspnego_ctx context_handle,
 339             gss_buffer_t mech_buf,
 340             heim_octet_string *mechListMIC
 341            )
 342 {
 343     OM_uint32 ret;
 344     gss_buffer_desc mic_buf;
 345 
 346     if (context_handle->verified_mic) {
 347         /* This doesn't make sense, we've already verified it? */
 348         *minor_status = 0;
 349         return GSS_S_DUPLICATE_TOKEN;
 350     }
 351 
 352     if (mechListMIC == NULL) {
 353         *minor_status = 0;
 354         return GSS_S_DEFECTIVE_TOKEN;
 355     }
 356 
 357     mic_buf.length = mechListMIC->length;
 358     mic_buf.value  = mechListMIC->data;
 359 
 360     ret = gss_verify_mic(minor_status,
 361                          context_handle->negotiated_ctx_id,
 362                          mech_buf,
 363                          &mic_buf,
 364                          NULL);
 365 
 366     if (ret != GSS_S_COMPLETE)
 367         ret = GSS_S_DEFECTIVE_TOKEN;
 368 
 369     return ret;
 370 }
 371 
 372 static OM_uint32
 373 select_mech(OM_uint32 *minor_status, MechType *mechType, int verify_p,
     /* [<][>][^][v][top][bottom][index][help] */
 374             gss_OID *mech_p)
 375 {
 376     char mechbuf[64];
 377     size_t mech_len;
 378     gss_OID_desc oid;
 379     gss_OID oidp;
 380     gss_OID_set mechs;
 381     int i;
 382     OM_uint32 ret, junk;
 383 
 384     ret = der_put_oid ((unsigned char *)mechbuf + sizeof(mechbuf) - 1,
 385                        sizeof(mechbuf),
 386                        mechType,
 387                        &mech_len);
 388     if (ret) {
 389         return GSS_S_DEFECTIVE_TOKEN;
 390     }
 391 
 392     oid.length   = mech_len;
 393     oid.elements = mechbuf + sizeof(mechbuf) - mech_len;
 394 
 395     if (gss_oid_equal(&oid, GSS_SPNEGO_MECHANISM)) {
 396         return GSS_S_BAD_MECH;
 397     }
 398 
 399     *minor_status = 0;
 400 
 401     /* Translate broken MS Kebreros OID */
 402     if (gss_oid_equal(&oid, &_gss_spnego_mskrb_mechanism_oid_desc))
 403             oidp = &_gss_spnego_krb5_mechanism_oid_desc;
 404     else
 405             oidp = &oid;
 406 
 407 
 408     ret = gss_indicate_mechs(&junk, &mechs);
 409     if (ret)
 410             return (ret);
 411 
 412     for (i = 0; i < mechs->count; i++)
 413             if (gss_oid_equal(&mechs->elements[i], oidp))
 414                     break;
 415 
 416     if (i == mechs->count) {
 417             gss_release_oid_set(&junk, &mechs);
 418             return GSS_S_BAD_MECH;
 419     }
 420     gss_release_oid_set(&junk, &mechs);
 421 
 422     ret = gss_duplicate_oid(minor_status,
 423                             &oid, /* possibly this should be oidp */
 424                             mech_p);
 425 
 426     if (verify_p) {
 427         gss_name_t name = GSS_C_NO_NAME;
 428         gss_buffer_desc namebuf;
 429         char *str = NULL, *host, hostname[MAXHOSTNAMELEN];
 430 
 431         host = getenv("GSSAPI_SPNEGO_NAME");
 432         if (host == NULL || issuid()) {
 433             if (gethostname(hostname, sizeof(hostname)) != 0) {
 434                 *minor_status = errno;
 435                 return GSS_S_FAILURE;
 436             }
 437             asprintf(&str, "host@%s", hostname);
 438             host = str;
 439         }
 440 
 441         namebuf.length = strlen(host);
 442         namebuf.value = host;
 443 
 444         ret = gss_import_name(minor_status, &namebuf,
 445                               GSS_C_NT_HOSTBASED_SERVICE, &name);
 446         if (str)
 447             free(str);
 448         if (ret != GSS_S_COMPLETE)
 449             return ret;
 450 
 451         ret = acceptor_approved(name, *mech_p);
 452         gss_release_name(&junk, &name);
 453     }
 454 
 455     return ret;
 456 }
 457 
 458 
 459 static OM_uint32
 460 acceptor_complete(OM_uint32 * minor_status,
     /* [<][>][^][v][top][bottom][index][help] */
 461                   gssspnego_ctx ctx,
 462                   int *get_mic,
 463                   gss_buffer_t mech_buf,
 464                   gss_buffer_t mech_input_token,
 465                   gss_buffer_t mech_output_token,
 466                   heim_octet_string *mic,
 467                   gss_buffer_t output_token)
 468 {
 469     OM_uint32 ret;
 470     int require_mic, verify_mic;
 471     gss_buffer_desc buf;
 472 
 473     buf.length = 0;
 474     buf.value = NULL;
 475 
 476     ret = _gss_spnego_require_mechlist_mic(minor_status, ctx, &require_mic);
 477     if (ret)
 478         return ret;
 479 
 480     ctx->require_mic = require_mic;
 481 
 482     if (mic != NULL)
 483         require_mic = 1;
 484 
 485     if (ctx->open && require_mic) {
 486         if (mech_input_token == GSS_C_NO_BUFFER) { /* Even/One */
 487             verify_mic = 1;
 488             *get_mic = 0;
 489         } else if (mech_output_token != GSS_C_NO_BUFFER &&
 490                    mech_output_token->length == 0) { /* Odd */
 491             *get_mic = verify_mic = 1;
 492         } else { /* Even/One */
 493             verify_mic = 0;
 494             *get_mic = 1;
 495         }
 496         
 497         if (verify_mic || get_mic) {
 498             int eret;
 499             size_t buf_len;
 500         
 501             ASN1_MALLOC_ENCODE(MechTypeList,
 502                                mech_buf->value, mech_buf->length,
 503                                &ctx->initiator_mech_types, &buf_len, eret);
 504             if (eret) {
 505                 *minor_status = eret;
 506                 return GSS_S_FAILURE;
 507             }
 508             if (buf.length != buf_len)
 509                 abort();
 510         }
 511         
 512         if (verify_mic) {
 513             ret = verify_mechlist_mic(minor_status, ctx, mech_buf, mic);
 514             if (ret) {
 515                 if (get_mic)
 516                     send_reject (minor_status, output_token);
 517                 if (buf.value)
 518                     free(buf.value);
 519                 return ret;
 520             }
 521             ctx->verified_mic = 1;
 522         }
 523         if (buf.value)
 524             free(buf.value);
 525 
 526     } else
 527         *get_mic = 0;
 528 
 529     return GSS_S_COMPLETE;
 530 }
 531 
 532 
 533 static OM_uint32
 534 acceptor_start
 535            (OM_uint32 * minor_status,
 536             gss_ctx_id_t * context_handle,
 537             const gss_cred_id_t acceptor_cred_handle,
 538             const gss_buffer_t input_token_buffer,
 539             const gss_channel_bindings_t input_chan_bindings,
 540             gss_name_t * src_name,
 541             gss_OID * mech_type,
 542             gss_buffer_t output_token,
 543             OM_uint32 * ret_flags,
 544             OM_uint32 * time_rec,
 545             gss_cred_id_t *delegated_cred_handle
 546            )
 547 {
 548     OM_uint32 ret, junk;
 549     NegotiationToken nt;
 550     size_t nt_len;
 551     NegTokenInit *ni;
 552     int i;
 553     gss_buffer_desc data;
 554     gss_buffer_t mech_input_token = GSS_C_NO_BUFFER;
 555     gss_buffer_desc mech_output_token;
 556     gss_buffer_desc mech_buf;
 557     gss_OID preferred_mech_type = GSS_C_NO_OID;
 558     gssspnego_ctx ctx;
 559     gssspnego_cred acceptor_cred = (gssspnego_cred)acceptor_cred_handle;
 560     int get_mic = 0;
 561     int first_ok = 0;
 562 
 563     mech_output_token.value = NULL;
 564     mech_output_token.length = 0;
 565     mech_buf.value = NULL;
 566 
 567     if (input_token_buffer->length == 0)
 568         return send_supported_mechs (minor_status, output_token);
 569         
 570     ret = _gss_spnego_alloc_sec_context(minor_status, context_handle);
 571     if (ret != GSS_S_COMPLETE)
 572         return ret;
 573 
 574     ctx = (gssspnego_ctx)*context_handle;
 575 
 576     /*
 577      * The GSS-API encapsulation is only present on the initial
 578      * context token (negTokenInit).
 579      */
 580     ret = gss_decapsulate_token (input_token_buffer,
 581                                  GSS_SPNEGO_MECHANISM,
 582                                  &data);
 583     if (ret)
 584         return ret;
 585 
 586     ret = decode_NegotiationToken(data.value, data.length, &nt, &nt_len);
 587     gss_release_buffer(minor_status, &data);
 588     if (ret) {
 589         *minor_status = ret;
 590         return GSS_S_DEFECTIVE_TOKEN;
 591     }
 592     if (nt.element != choice_NegotiationToken_negTokenInit) {
 593         *minor_status = 0;
 594         return GSS_S_DEFECTIVE_TOKEN;
 595     }
 596     ni = &nt.u.negTokenInit;
 597 
 598     if (ni->mechTypes.len < 1) {
 599         free_NegotiationToken(&nt);
 600         *minor_status = 0;
 601         return GSS_S_DEFECTIVE_TOKEN;
 602     }
 603 
 604     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
 605 
 606     ret = copy_MechTypeList(&ni->mechTypes, &ctx->initiator_mech_types);
 607     if (ret) {
 608         HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 609         free_NegotiationToken(&nt);
 610         *minor_status = ret;
 611         return GSS_S_FAILURE;
 612     }
 613 
 614     /*
 615      * First we try the opportunistic token if we have support for it,
 616      * don't try to verify we have credential for the token,
 617      * gss_accept_sec_context() will (hopefully) tell us that.
 618      * If that failes,
 619      */
 620 
 621     ret = select_mech(minor_status,
 622                       &ni->mechTypes.val[0],
 623                       0,
 624                       &preferred_mech_type);
 625 
 626     if (ret == 0 && ni->mechToken != NULL) {
 627         gss_cred_id_t mech_delegated_cred = GSS_C_NO_CREDENTIAL;
 628         gss_cred_id_t mech_cred;
 629         gss_buffer_desc ibuf;
 630 
 631         ibuf.length = ni->mechToken->length;
 632         ibuf.value = ni->mechToken->data;
 633         mech_input_token = &ibuf;
 634 
 635         if (acceptor_cred != NULL)
 636             mech_cred = acceptor_cred->negotiated_cred_id;
 637         else
 638             mech_cred = GSS_C_NO_CREDENTIAL;
 639         
 640         if (ctx->mech_src_name != GSS_C_NO_NAME)
 641             gss_release_name(&junk, &ctx->mech_src_name);
 642         
 643         ret = gss_accept_sec_context(minor_status,
 644                                      &ctx->negotiated_ctx_id,
 645                                      mech_cred,
 646                                      mech_input_token,
 647                                      input_chan_bindings,
 648                                      &ctx->mech_src_name,
 649                                      &ctx->negotiated_mech_type,
 650                                      &mech_output_token,
 651                                      &ctx->mech_flags,
 652                                      &ctx->mech_time_rec,
 653                                      &mech_delegated_cred);
 654 
 655         if (mech_delegated_cred && delegated_cred_handle) {
 656             _gss_spnego_alloc_cred(&junk,
 657                                    mech_delegated_cred,
 658                                    delegated_cred_handle);
 659         } else if (mech_delegated_cred != GSS_C_NO_CREDENTIAL)
 660             gss_release_cred(&junk, &mech_delegated_cred);
 661 
 662         if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
 663             ctx->preferred_mech_type = preferred_mech_type;
 664             ctx->negotiated_mech_type = preferred_mech_type;
 665             if (ret == GSS_S_COMPLETE)
 666                 ctx->open = 1;
 667 
 668             ret = acceptor_complete(minor_status,
 669                                     ctx,
 670                                     &get_mic,
 671                                     &mech_buf,
 672                                     mech_input_token,
 673                                     &mech_output_token,
 674                                     ni->mechListMIC,
 675                                     output_token);
 676             if (ret != GSS_S_COMPLETE)
 677                 goto out;
 678 
 679             first_ok = 1;
 680         } else {
 681             gss_mg_collect_error(preferred_mech_type, ret, *minor_status);
 682         }
 683     }
 684 
 685     /*
 686      * If opportunistic token failed, lets try the other mechs.
 687      */
 688 
 689     if (!first_ok && ni->mechToken != NULL) {
 690 
 691         preferred_mech_type = GSS_C_NO_OID;
 692 
 693         /* Call glue layer to find first mech we support */
 694         for (i = 1; i < ni->mechTypes.len; ++i) {
 695             ret = select_mech(minor_status,
 696                               &ni->mechTypes.val[i],
 697                               1,
 698                               &preferred_mech_type);
 699             if (ret == 0)
 700                 break;
 701         }
 702         if (preferred_mech_type == GSS_C_NO_OID) {
 703             HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 704             free_NegotiationToken(&nt);
 705             return ret;
 706         }
 707 
 708         ctx->preferred_mech_type = preferred_mech_type;
 709         ctx->negotiated_mech_type = preferred_mech_type;
 710     }
 711 
 712     /*
 713      * The initial token always have a response
 714      */
 715 
 716     ret = send_accept (minor_status,
 717                        ctx,
 718                        &mech_output_token,
 719                        1,
 720                        get_mic ? &mech_buf : NULL,
 721                        output_token);
 722     if (ret)
 723         goto out;
 724 
 725 out:
 726     if (mech_output_token.value != NULL)
 727         gss_release_buffer(&junk, &mech_output_token);
 728     if (mech_buf.value != NULL) {
 729         free(mech_buf.value);
 730         mech_buf.value = NULL;
 731     }
 732     free_NegotiationToken(&nt);
 733 
 734 
 735     if (ret == GSS_S_COMPLETE) {
 736         if (src_name != NULL && ctx->mech_src_name != NULL) {
 737             spnego_name name;
 738 
 739             name = calloc(1, sizeof(*name));
 740             if (name) {
 741                 name->mech = ctx->mech_src_name;
 742                 ctx->mech_src_name = NULL;
 743                 *src_name = (gss_name_t)name;
 744             }
 745         }
 746     }
 747 
 748     if (mech_type != NULL)
 749         *mech_type = ctx->negotiated_mech_type;
 750     if (ret_flags != NULL)
 751         *ret_flags = ctx->mech_flags;
 752     if (time_rec != NULL)
 753         *time_rec = ctx->mech_time_rec;
 754 
 755     if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
 756         HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 757         return ret;
 758     }
 759 
 760     _gss_spnego_internal_delete_sec_context(&junk, context_handle,
 761                                             GSS_C_NO_BUFFER);
 762 
 763     return ret;
 764 }
 765 
 766 
 767 static OM_uint32
 768 acceptor_continue
 769            (OM_uint32 * minor_status,
 770             gss_ctx_id_t * context_handle,
 771             const gss_cred_id_t acceptor_cred_handle,
 772             const gss_buffer_t input_token_buffer,
 773             const gss_channel_bindings_t input_chan_bindings,
 774             gss_name_t * src_name,
 775             gss_OID * mech_type,
 776             gss_buffer_t output_token,
 777             OM_uint32 * ret_flags,
 778             OM_uint32 * time_rec,
 779             gss_cred_id_t *delegated_cred_handle
 780            )
 781 {
 782     OM_uint32 ret, ret2, minor, junk;
 783     NegotiationToken nt;
 784     size_t nt_len;
 785     NegTokenResp *na;
 786     unsigned int negResult = accept_incomplete;
 787     gss_buffer_t mech_input_token = GSS_C_NO_BUFFER;
 788     gss_buffer_t mech_output_token = GSS_C_NO_BUFFER;
 789     gss_buffer_desc mech_buf;
 790     gssspnego_ctx ctx;
 791     gssspnego_cred acceptor_cred = (gssspnego_cred)acceptor_cred_handle;
 792 
 793     mech_buf.value = NULL;
 794 
 795     ctx = (gssspnego_ctx)*context_handle;
 796 
 797     /*
 798      * The GSS-API encapsulation is only present on the initial
 799      * context token (negTokenInit).
 800      */
 801 
 802     ret = decode_NegotiationToken(input_token_buffer->value,
 803                                   input_token_buffer->length,
 804                                   &nt, &nt_len);
 805     if (ret) {
 806         *minor_status = ret;
 807         return GSS_S_DEFECTIVE_TOKEN;
 808     }
 809     if (nt.element != choice_NegotiationToken_negTokenResp) {
 810         *minor_status = 0;
 811         return GSS_S_DEFECTIVE_TOKEN;
 812     }
 813     na = &nt.u.negTokenResp;
 814 
 815     if (na->negResult != NULL) {
 816         negResult = *(na->negResult);
 817     }
 818 
 819     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
 820 
 821     {
 822         gss_buffer_desc ibuf, obuf;
 823         int require_mic, get_mic = 0;
 824         int require_response;
 825         heim_octet_string *mic;
 826 
 827         if (na->responseToken != NULL) {
 828             ibuf.length = na->responseToken->length;
 829             ibuf.value = na->responseToken->data;
 830             mech_input_token = &ibuf;
 831         } else {
 832             ibuf.value = NULL;
 833             ibuf.length = 0;
 834         }
 835 
 836         if (mech_input_token != GSS_C_NO_BUFFER) {
 837             gss_cred_id_t mech_cred;
 838             gss_cred_id_t mech_delegated_cred = GSS_C_NO_CREDENTIAL;
 839 
 840             if (acceptor_cred != NULL)
 841                 mech_cred = acceptor_cred->negotiated_cred_id;
 842             else
 843                 mech_cred = GSS_C_NO_CREDENTIAL;
 844 
 845             if (ctx->mech_src_name != GSS_C_NO_NAME)
 846                 gss_release_name(&minor, &ctx->mech_src_name);
 847 
 848             ret = gss_accept_sec_context(&minor,
 849                                          &ctx->negotiated_ctx_id,
 850                                          mech_cred,
 851                                          mech_input_token,
 852                                          input_chan_bindings,
 853                                          &ctx->mech_src_name,
 854                                          &ctx->negotiated_mech_type,
 855                                          &obuf,
 856                                          &ctx->mech_flags,
 857                                          &ctx->mech_time_rec,
 858                                          &mech_delegated_cred);
 859 
 860             if (mech_delegated_cred && delegated_cred_handle) {
 861                 _gss_spnego_alloc_cred(&junk,
 862                                        mech_delegated_cred,
 863                                        delegated_cred_handle);
 864             } else if (mech_delegated_cred != GSS_C_NO_CREDENTIAL)
 865                 gss_release_cred(&junk, &mech_delegated_cred);
 866 
 867             if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
 868                 mech_output_token = &obuf;
 869             }
 870             if (ret != GSS_S_COMPLETE && ret != GSS_S_CONTINUE_NEEDED) {
 871                 free_NegotiationToken(&nt);
 872                 gss_mg_collect_error(ctx->negotiated_mech_type, ret, minor);
 873                 send_reject (minor_status, output_token);
 874                 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 875                 return ret;
 876             }
 877             if (ret == GSS_S_COMPLETE)
 878                 ctx->open = 1;
 879         } else
 880             ret = GSS_S_COMPLETE;
 881 
 882         ret2 = _gss_spnego_require_mechlist_mic(minor_status,
 883                                                 ctx,
 884                                                 &require_mic);
 885         if (ret2)
 886             goto out;
 887 
 888         ctx->require_mic = require_mic;
 889 
 890         mic = na->mechListMIC;
 891         if (mic != NULL)
 892             require_mic = 1;
 893 
 894         if (ret == GSS_S_COMPLETE)
 895             ret = acceptor_complete(minor_status,
 896                                     ctx,
 897                                     &get_mic,
 898                                     &mech_buf,
 899                                     mech_input_token,
 900                                     mech_output_token,
 901                                     na->mechListMIC,
 902                                     output_token);
 903 
 904         if (ctx->mech_flags & GSS_C_DCE_STYLE)
 905             require_response = (negResult != accept_completed);
 906         else
 907             require_response = 0;
 908 
 909         /*
 910          * Check whether we need to send a result: there should be only
 911          * one accept_completed response sent in the entire negotiation
 912          */
 913         if ((mech_output_token != GSS_C_NO_BUFFER &&
 914              mech_output_token->length != 0)
 915             || (ctx->open && negResult == accept_incomplete)
 916             || require_response
 917             || get_mic) {
 918             ret2 = send_accept (minor_status,
 919                                 ctx,
 920                                 mech_output_token,
 921                                 0,
 922                                 get_mic ? &mech_buf : NULL,
 923                                 output_token);
 924             if (ret2)
 925                 goto out;
 926         }
 927 
 928      out:
 929         if (ret2 != GSS_S_COMPLETE)
 930             ret = ret2;
 931         if (mech_output_token != NULL)
 932             gss_release_buffer(&minor, mech_output_token);
 933         if (mech_buf.value != NULL)
 934             free(mech_buf.value);
 935         free_NegotiationToken(&nt);
 936     }
 937 
 938     if (ret == GSS_S_COMPLETE) {
 939         if (src_name != NULL && ctx->mech_src_name != NULL) {
 940             spnego_name name;
 941 
 942             name = calloc(1, sizeof(*name));
 943             if (name) {
 944                 name->mech = ctx->mech_src_name;
 945                 ctx->mech_src_name = NULL;
 946                 *src_name = (gss_name_t)name;
 947             }
 948         }
 949     }
 950 
 951     if (mech_type != NULL)
 952         *mech_type = ctx->negotiated_mech_type;
 953     if (ret_flags != NULL)
 954         *ret_flags = ctx->mech_flags;
 955     if (time_rec != NULL)
 956         *time_rec = ctx->mech_time_rec;
 957 
 958     if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
 959         HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 960         return ret;
 961     }
 962 
 963     _gss_spnego_internal_delete_sec_context(&minor, context_handle,
 964                                    GSS_C_NO_BUFFER);
 965 
 966     return ret;
 967 }
 968 
 969 OM_uint32
 970 _gss_spnego_accept_sec_context
 971            (OM_uint32 * minor_status,
 972             gss_ctx_id_t * context_handle,
 973             const gss_cred_id_t acceptor_cred_handle,
 974             const gss_buffer_t input_token_buffer,
 975             const gss_channel_bindings_t input_chan_bindings,
 976             gss_name_t * src_name,
 977             gss_OID * mech_type,
 978             gss_buffer_t output_token,
 979             OM_uint32 * ret_flags,
 980             OM_uint32 * time_rec,
 981             gss_cred_id_t *delegated_cred_handle
 982            )
 983 {
 984     _gss_accept_sec_context_t *func;
 985 
 986     *minor_status = 0;
 987 
 988     output_token->length = 0;
 989     output_token->value  = NULL;
 990 
 991     if (src_name != NULL)
 992         *src_name = GSS_C_NO_NAME;
 993     if (mech_type != NULL)
 994         *mech_type = GSS_C_NO_OID;
 995     if (ret_flags != NULL)
 996         *ret_flags = 0;
 997     if (time_rec != NULL)
 998         *time_rec = 0;
 999     if (delegated_cred_handle != NULL)
1000         *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
1001 
1002 
1003     if (*context_handle == GSS_C_NO_CONTEXT)
1004         func = acceptor_start;
1005     else
1006         func = acceptor_continue;
1007 
1008 
1009     return (*func)(minor_status, context_handle, acceptor_cred_handle,
1010                    input_token_buffer, input_chan_bindings,
1011                    src_name, mech_type, output_token, ret_flags,
1012                    time_rec, delegated_cred_handle);
1013 }

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