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

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

DEFINITIONS

This source file includes following definitions.
  1. set_addresses
  2. _gsskrb5_create_ctx
  3. gsskrb5_get_creds
  4. gsskrb5_initiator_ready
  5. do_delegation

   1 /*
   2  * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
   3  * (Royal Institute of Technology, Stockholm, Sweden).
   4  * All rights reserved.
   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 "krb5/gsskrb5_locl.h"
  35 
  36 RCSID("$Id$");
  37 
  38 /*
  39  * copy the addresses from `input_chan_bindings' (if any) to
  40  * the auth context `ac'
  41  */
  42 
  43 static OM_uint32
  44 set_addresses (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
  45                krb5_auth_context ac,
  46                const gss_channel_bindings_t input_chan_bindings)        
  47 {
  48     /* Port numbers are expected to be in application_data.value,
  49      * initator's port first */
  50 
  51     krb5_address initiator_addr, acceptor_addr;
  52     krb5_error_code kret;
  53 
  54     if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS
  55         || input_chan_bindings->application_data.length !=
  56         2 * sizeof(ac->local_port))
  57         return 0;
  58 
  59     memset(&initiator_addr, 0, sizeof(initiator_addr));
  60     memset(&acceptor_addr, 0, sizeof(acceptor_addr));
  61 
  62     ac->local_port =
  63         *(int16_t *) input_chan_bindings->application_data.value;
  64 
  65     ac->remote_port =
  66         *((int16_t *) input_chan_bindings->application_data.value + 1);
  67 
  68     kret = _gsskrb5i_address_to_krb5addr(context,
  69                                          input_chan_bindings->acceptor_addrtype,
  70                                          &input_chan_bindings->acceptor_address,
  71                                          ac->remote_port,
  72                                          &acceptor_addr);
  73     if (kret)
  74         return kret;
  75 
  76     kret = _gsskrb5i_address_to_krb5addr(context,
  77                                          input_chan_bindings->initiator_addrtype,
  78                                          &input_chan_bindings->initiator_address,
  79                                          ac->local_port,
  80                                          &initiator_addr);
  81     if (kret) {
  82         krb5_free_address (context, &acceptor_addr);
  83         return kret;
  84     }
  85 
  86     kret = krb5_auth_con_setaddrs(context,
  87                                   ac,
  88                                   &initiator_addr,  /* local address */
  89                                   &acceptor_addr);  /* remote address */
  90 
  91     krb5_free_address (context, &initiator_addr);
  92     krb5_free_address (context, &acceptor_addr);
  93 
  94 #if 0
  95     free(input_chan_bindings->application_data.value);
  96     input_chan_bindings->application_data.value = NULL;
  97     input_chan_bindings->application_data.length = 0;
  98 #endif
  99 
 100     return kret;
 101 }
 102 
 103 OM_uint32
 104 _gsskrb5_create_ctx(
     /* [<][>][^][v][top][bottom][index][help] */
 105         OM_uint32 * minor_status,
 106         gss_ctx_id_t * context_handle,
 107         krb5_context context,
 108         const gss_channel_bindings_t input_chan_bindings,
 109         enum gss_ctx_id_t_state state)
 110 {
 111     krb5_error_code kret;
 112     gsskrb5_ctx ctx;
 113 
 114     *context_handle = NULL;
 115 
 116     ctx = malloc(sizeof(*ctx));
 117     if (ctx == NULL) {
 118         *minor_status = ENOMEM;
 119         return GSS_S_FAILURE;
 120     }
 121     ctx->auth_context           = NULL;
 122     ctx->source                 = NULL;
 123     ctx->target                 = NULL;
 124     ctx->kcred                  = NULL;
 125     ctx->ccache                 = NULL;
 126     ctx->state                  = state;
 127     ctx->flags                  = 0;
 128     ctx->more_flags             = 0;
 129     ctx->service_keyblock       = NULL;
 130     ctx->ticket                 = NULL;
 131     krb5_data_zero(&ctx->fwd_data);
 132     ctx->lifetime               = GSS_C_INDEFINITE;
 133     ctx->order                  = NULL;
 134     HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex);
 135 
 136     kret = krb5_auth_con_init (context, &ctx->auth_context);
 137     if (kret) {
 138         *minor_status = kret;
 139         HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
 140         return GSS_S_FAILURE;
 141     }
 142 
 143     kret = set_addresses(context, ctx->auth_context, input_chan_bindings);
 144     if (kret) {
 145         *minor_status = kret;
 146 
 147         HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
 148 
 149         krb5_auth_con_free(context, ctx->auth_context);
 150 
 151         return GSS_S_BAD_BINDINGS;
 152     }
 153 
 154     /*
 155      * We need a sequence number
 156      */
 157 
 158     krb5_auth_con_addflags(context,
 159                            ctx->auth_context,
 160                            KRB5_AUTH_CONTEXT_DO_SEQUENCE |
 161                            KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED,
 162                            NULL);
 163 
 164     *context_handle = (gss_ctx_id_t)ctx;
 165 
 166     return GSS_S_COMPLETE;
 167 }
 168 
 169 
 170 static OM_uint32
 171 gsskrb5_get_creds(
     /* [<][>][^][v][top][bottom][index][help] */
 172         OM_uint32 * minor_status,
 173         krb5_context context,
 174         krb5_ccache ccache,
 175         gsskrb5_ctx ctx,
 176         const gss_name_t target_name,
 177         int use_dns,
 178         OM_uint32 time_req,
 179         OM_uint32 * time_rec,
 180         krb5_creds ** cred)
 181 {
 182     OM_uint32 ret;
 183     krb5_error_code kret;
 184     krb5_creds this_cred;
 185     OM_uint32 lifetime_rec;
 186 
 187     *cred = NULL;
 188 
 189     if (ctx->target) {
 190         krb5_free_principal(context, ctx->target);
 191         ctx->target = NULL;
 192     }
 193 
 194     ret = _gsskrb5_canon_name(minor_status, context, use_dns,
 195                               target_name, &ctx->target);
 196     if (ret)
 197         return ret;
 198 
 199     memset(&this_cred, 0, sizeof(this_cred));
 200     this_cred.client = ctx->source;
 201     this_cred.server = ctx->target;
 202 
 203     if (time_req && time_req != GSS_C_INDEFINITE) {
 204         krb5_timestamp ts;
 205 
 206         krb5_timeofday (context, &ts);
 207         this_cred.times.endtime = ts + time_req;
 208     } else {
 209         this_cred.times.endtime   = 0;
 210     }
 211 
 212     this_cred.session.keytype = KEYTYPE_NULL;
 213 
 214     kret = krb5_get_credentials(context,
 215                                 0,
 216                                 ccache,
 217                                 &this_cred,
 218                                 cred);
 219     if (kret) {
 220         *minor_status = kret;
 221         return GSS_S_FAILURE;
 222     }
 223 
 224     ctx->lifetime = (*cred)->times.endtime;
 225 
 226     ret = _gsskrb5_lifetime_left(minor_status, context,
 227                                  ctx->lifetime, &lifetime_rec);
 228     if (ret) return ret;
 229 
 230     if (lifetime_rec == 0) {
 231         *minor_status = 0;
 232         return GSS_S_CONTEXT_EXPIRED;
 233     }
 234 
 235     if (time_rec) *time_rec = lifetime_rec;
 236 
 237     return GSS_S_COMPLETE;
 238 }
 239 
 240 static OM_uint32
 241 gsskrb5_initiator_ready(
     /* [<][>][^][v][top][bottom][index][help] */
 242         OM_uint32 * minor_status,
 243         gsskrb5_ctx ctx,
 244         krb5_context context)
 245 {
 246     OM_uint32 ret;
 247     int32_t seq_number;
 248     int is_cfx = 0;
 249     OM_uint32 flags = ctx->flags;
 250 
 251     krb5_free_creds(context, ctx->kcred);
 252     ctx->kcred = NULL;
 253 
 254     if (ctx->more_flags & CLOSE_CCACHE)
 255         krb5_cc_close(context, ctx->ccache);
 256     ctx->ccache = NULL;
 257 
 258     krb5_auth_getremoteseqnumber (context, ctx->auth_context, &seq_number);
 259 
 260     _gsskrb5i_is_cfx(ctx, &is_cfx);
 261 
 262     ret = _gssapi_msg_order_create(minor_status,
 263                                    &ctx->order,
 264                                    _gssapi_msg_order_f(flags),
 265                                    seq_number, 0, is_cfx);
 266     if (ret) return ret;
 267 
 268     ctx->state  = INITIATOR_READY;
 269     ctx->more_flags     |= OPEN;
 270 
 271     return GSS_S_COMPLETE;
 272 }
 273 
 274 /*
 275  * handle delegated creds in init-sec-context
 276  */
 277 
 278 static void
 279 do_delegation (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 280                krb5_auth_context ac,
 281                krb5_ccache ccache,
 282                krb5_creds *cred,
 283                krb5_const_principal name,
 284                krb5_data *fwd_data,
 285                uint32_t flagmask,
 286                uint32_t *flags)
 287 {
 288     krb5_creds creds;
 289     KDCOptions fwd_flags;
 290     krb5_error_code kret;
 291 
 292     memset (&creds, 0, sizeof(creds));
 293     krb5_data_zero (fwd_data);
 294 
 295     kret = krb5_cc_get_principal(context, ccache, &creds.client);
 296     if (kret)
 297         goto out;
 298 
 299     kret = krb5_build_principal(context,
 300                                 &creds.server,
 301                                 strlen(creds.client->realm),
 302                                 creds.client->realm,
 303                                 KRB5_TGS_NAME,
 304                                 creds.client->realm,
 305                                 NULL);
 306     if (kret)
 307         goto out;
 308 
 309     creds.times.endtime = 0;
 310 
 311     memset(&fwd_flags, 0, sizeof(fwd_flags));
 312     fwd_flags.forwarded = 1;
 313     fwd_flags.forwardable = 1;
 314 
 315     if ( /*target_name->name.name_type != KRB5_NT_SRV_HST ||*/
 316         name->name.name_string.len < 2)
 317         goto out;
 318 
 319     kret = krb5_get_forwarded_creds(context,
 320                                     ac,
 321                                     ccache,
 322                                     KDCOptions2int(fwd_flags),
 323                                     name->name.name_string.val[1],
 324                                     &creds,
 325                                     fwd_data);
 326 
 327  out:
 328     if (kret)
 329         *flags &= ~flagmask;
 330     else
 331         *flags |= flagmask;
 332 
 333     if (creds.client)
 334         krb5_free_principal(context, creds.client);
 335     if (creds.server)
 336         krb5_free_principal(context, creds.server);
 337 }
 338 
 339 /*
 340  * first stage of init-sec-context
 341  */
 342 
 343 static OM_uint32
 344 init_auth
 345 (OM_uint32 * minor_status,
 346  gsskrb5_cred cred,
 347  gsskrb5_ctx ctx,
 348  krb5_context context,
 349  gss_name_t name,
 350  const gss_OID mech_type,
 351  OM_uint32 req_flags,
 352  OM_uint32 time_req,
 353  const gss_buffer_t input_token,
 354  gss_OID * actual_mech_type,
 355  gss_buffer_t output_token,
 356  OM_uint32 * ret_flags,
 357  OM_uint32 * time_rec
 358     )
 359 {
 360     OM_uint32 ret = GSS_S_FAILURE;
 361     krb5_error_code kret;
 362     krb5_data outbuf;
 363     krb5_data fwd_data;
 364     OM_uint32 lifetime_rec;
 365     int allow_dns = 1;
 366 
 367     krb5_data_zero(&outbuf);
 368     krb5_data_zero(&fwd_data);
 369 
 370     *minor_status = 0;
 371 
 372     if (actual_mech_type)
 373         *actual_mech_type = GSS_KRB5_MECHANISM;
 374 
 375     if (cred == NULL) {
 376         kret = krb5_cc_default (context, &ctx->ccache);
 377         if (kret) {
 378             *minor_status = kret;
 379             ret = GSS_S_FAILURE;
 380             goto failure;
 381         }
 382         ctx->more_flags |= CLOSE_CCACHE;
 383     } else
 384         ctx->ccache = cred->ccache;
 385 
 386     kret = krb5_cc_get_principal (context, ctx->ccache, &ctx->source);
 387     if (kret) {
 388         *minor_status = kret;
 389         ret = GSS_S_FAILURE;
 390         goto failure;
 391     }
 392 
 393     ret = _gss_DES3_get_mic_compat(minor_status, ctx, context);
 394     if (ret)
 395         goto failure;
 396 
 397 
 398     /*
 399      * This is hideous glue for (NFS) clients that wants to limit the
 400      * available enctypes to what it can support (encryption in
 401      * kernel). If there is no enctypes selected for this credential,
 402      * reset it to the default set of enctypes.
 403      */
 404     {
 405         krb5_enctype *enctypes = NULL;
 406 
 407         if (cred && cred->enctypes)
 408             enctypes = cred->enctypes;
 409         krb5_set_default_in_tkt_etypes(context, enctypes);
 410     }
 411 
 412     /* canon name if needed for client + target realm */
 413     kret = krb5_cc_get_config(context, ctx->ccache, NULL,
 414                               "realm-config", &outbuf);
 415     if (kret == 0) {
 416         /* XXX 2 is no server canon */
 417         if (outbuf.length < 1 || ((((unsigned char *)outbuf.data)[0]) & 2))
 418             allow_dns = 0;
 419         krb5_data_free(&outbuf);
 420     }
 421 
 422     /*
 423      * First we try w/o dns, hope that the KDC have register alias
 424      * (and referrals if cross realm) for this principal. If that
 425      * fails and if we are allowed to using this realm try again with
 426      * DNS canonicalizion.
 427      */
 428     ret = gsskrb5_get_creds(minor_status, context, ctx->ccache,
 429                             ctx, name, 0, time_req, 
 430                             time_rec, &ctx->kcred);
 431     if (ret && allow_dns)
 432         ret = gsskrb5_get_creds(minor_status, context, ctx->ccache,
 433                                 ctx, name, 1, time_req, 
 434                                 time_rec, &ctx->kcred);
 435     if (ret)
 436         goto failure;
 437 
 438     ctx->lifetime = ctx->kcred->times.endtime;
 439 
 440     ret = _gsskrb5_lifetime_left(minor_status,
 441                                  context,
 442                                  ctx->lifetime,
 443                                  &lifetime_rec);
 444     if (ret)
 445         goto failure;
 446 
 447     if (lifetime_rec == 0) {
 448         *minor_status = 0;
 449         ret = GSS_S_CONTEXT_EXPIRED;
 450         goto failure;
 451     }
 452 
 453     krb5_auth_con_setkey(context,
 454                          ctx->auth_context,
 455                          &ctx->kcred->session);
 456 
 457     kret = krb5_auth_con_generatelocalsubkey(context,
 458                                              ctx->auth_context,
 459                                              &ctx->kcred->session);
 460     if(kret) {
 461         *minor_status = kret;
 462         ret = GSS_S_FAILURE;
 463         goto failure;
 464     }
 465 
 466     return GSS_S_COMPLETE;
 467 
 468 failure:
 469     if (ctx->ccache && (ctx->more_flags & CLOSE_CCACHE))
 470         krb5_cc_close(context, ctx->ccache);
 471     ctx->ccache = NULL;
 472 
 473     return ret;
 474 
 475 }
 476 
 477 static OM_uint32
 478 init_auth_restart
 479 (OM_uint32 * minor_status,
 480  gsskrb5_cred cred,
 481  gsskrb5_ctx ctx,
 482  krb5_context context,
 483  OM_uint32 req_flags,
 484  const gss_channel_bindings_t input_chan_bindings,
 485  const gss_buffer_t input_token,
 486  gss_OID * actual_mech_type,
 487  gss_buffer_t output_token,
 488  OM_uint32 * ret_flags,
 489  OM_uint32 * time_rec
 490     )
 491 {
 492     OM_uint32 ret = GSS_S_FAILURE;
 493     krb5_error_code kret;
 494     krb5_flags ap_options;
 495     krb5_data outbuf;
 496     uint32_t flags;
 497     krb5_data authenticator;
 498     Checksum cksum;
 499     krb5_enctype enctype;
 500     krb5_data fwd_data, timedata;
 501     int32_t offset = 0, oldoffset;
 502     uint32_t flagmask;
 503 
 504     krb5_data_zero(&outbuf);
 505     krb5_data_zero(&fwd_data);
 506 
 507     *minor_status = 0;
 508 
 509     /*
 510      * If the credential doesn't have ok-as-delegate, check if there
 511      * is a realm setting and use that.
 512      */
 513     if (!ctx->kcred->flags.b.ok_as_delegate) {
 514         krb5_data data;
 515         
 516         ret = krb5_cc_get_config(context, ctx->ccache, NULL,
 517                                  "realm-config", &data);
 518         if (ret == 0) {
 519             /* XXX 1 is use ok-as-delegate */
 520             if (data.length < 1 || ((((unsigned char *)data.data)[0]) & 1) == 0)
 521                 req_flags &= ~(GSS_C_DELEG_FLAG|GSS_C_DELEG_POLICY_FLAG);
 522             krb5_data_free(&data);
 523         }
 524     }
 525 
 526     flagmask = 0;
 527 
 528     /* if we used GSS_C_DELEG_POLICY_FLAG, trust KDC */
 529     if ((req_flags & GSS_C_DELEG_POLICY_FLAG)
 530         && ctx->kcred->flags.b.ok_as_delegate)
 531         flagmask |= GSS_C_DELEG_FLAG | GSS_C_DELEG_POLICY_FLAG;
 532     /* if there still is a GSS_C_DELEG_FLAG, use that */
 533     if (req_flags & GSS_C_DELEG_FLAG)
 534         flagmask |= GSS_C_DELEG_FLAG;
 535 
 536 
 537     flags = 0;
 538     ap_options = 0;
 539     if (flagmask & GSS_C_DELEG_FLAG) {
 540         do_delegation (context,
 541                        ctx->auth_context,
 542                        ctx->ccache, ctx->kcred, ctx->target,
 543                        &fwd_data, flagmask, &flags);
 544     }
 545 
 546     if (req_flags & GSS_C_MUTUAL_FLAG) {
 547         flags |= GSS_C_MUTUAL_FLAG;
 548         ap_options |= AP_OPTS_MUTUAL_REQUIRED;
 549     }
 550 
 551     if (req_flags & GSS_C_REPLAY_FLAG)
 552         flags |= GSS_C_REPLAY_FLAG;
 553     if (req_flags & GSS_C_SEQUENCE_FLAG)
 554         flags |= GSS_C_SEQUENCE_FLAG;
 555     if (req_flags & GSS_C_ANON_FLAG)
 556         ;                               /* XXX */
 557     if (req_flags & GSS_C_DCE_STYLE) {
 558         /* GSS_C_DCE_STYLE implies GSS_C_MUTUAL_FLAG */
 559         flags |= GSS_C_DCE_STYLE | GSS_C_MUTUAL_FLAG;
 560         ap_options |= AP_OPTS_MUTUAL_REQUIRED;
 561     }
 562     if (req_flags & GSS_C_IDENTIFY_FLAG)
 563         flags |= GSS_C_IDENTIFY_FLAG;
 564     if (req_flags & GSS_C_EXTENDED_ERROR_FLAG)
 565         flags |= GSS_C_EXTENDED_ERROR_FLAG;
 566 
 567     if (req_flags & GSS_C_CONF_FLAG) {
 568         flags |= GSS_C_CONF_FLAG;
 569     }
 570     if (req_flags & GSS_C_INTEG_FLAG) {
 571         flags |= GSS_C_INTEG_FLAG;
 572     }
 573     if (cred == NULL || !(cred->cred_flags & GSS_CF_NO_CI_FLAGS)) {
 574         flags |= GSS_C_CONF_FLAG;
 575         flags |= GSS_C_INTEG_FLAG;
 576     }
 577     flags |= GSS_C_TRANS_FLAG;
 578 
 579     if (ret_flags)
 580         *ret_flags = flags;
 581     ctx->flags = flags;
 582     ctx->more_flags |= LOCAL;
 583 
 584     ret = _gsskrb5_create_8003_checksum (minor_status,
 585                                          input_chan_bindings,
 586                                          flags,
 587                                          &fwd_data,
 588                                          &cksum);
 589     krb5_data_free (&fwd_data);
 590     if (ret)
 591         goto failure;
 592 
 593     enctype = ctx->auth_context->keyblock->keytype;
 594 
 595     ret = krb5_cc_get_config(context, ctx->ccache, ctx->target,
 596                              "time-offset", &timedata);
 597     if (ret == 0) {
 598         if (timedata.length == 4) {
 599             const u_char *p = timedata.data;
 600             offset = (p[0] <<24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
 601         }
 602         krb5_data_free(&timedata);
 603     }
 604 
 605     if (offset) {
 606         krb5_get_kdc_sec_offset (context, &oldoffset, NULL);
 607         krb5_set_kdc_sec_offset (context, offset, -1);
 608     }
 609 
 610     kret = krb5_build_authenticator (context,
 611                                      ctx->auth_context,
 612                                      enctype,
 613                                      ctx->kcred,
 614                                      &cksum,
 615                                      NULL,
 616                                      &authenticator,
 617                                      KRB5_KU_AP_REQ_AUTH);
 618 
 619     if (kret) {
 620         if (offset)
 621             krb5_set_kdc_sec_offset (context, oldoffset, -1);
 622         *minor_status = kret;
 623         ret = GSS_S_FAILURE;
 624         goto failure;
 625     }
 626 
 627     kret = krb5_build_ap_req (context,
 628                               enctype,
 629                               ctx->kcred,
 630                               ap_options,
 631                               authenticator,
 632                               &outbuf);
 633     if (offset)
 634         krb5_set_kdc_sec_offset (context, oldoffset, -1);
 635     if (kret) {
 636         *minor_status = kret;
 637         ret = GSS_S_FAILURE;
 638         goto failure;
 639     }
 640 
 641     if (flags & GSS_C_DCE_STYLE) {
 642         output_token->value = outbuf.data;
 643         output_token->length = outbuf.length;
 644     } else {
 645         ret = _gsskrb5_encapsulate (minor_status, &outbuf, output_token,
 646                                     (u_char *)"\x01\x00", GSS_KRB5_MECHANISM);
 647         krb5_data_free (&outbuf);
 648         if (ret)
 649             goto failure;
 650     }
 651 
 652     free_Checksum(&cksum);
 653 
 654     if (flags & GSS_C_MUTUAL_FLAG) {
 655         ctx->state = INITIATOR_WAIT_FOR_MUTAL;
 656         return GSS_S_CONTINUE_NEEDED;
 657     }
 658 
 659     return gsskrb5_initiator_ready(minor_status, ctx, context);
 660 failure:
 661     if (ctx->ccache && (ctx->more_flags & CLOSE_CCACHE))
 662         krb5_cc_close(context, ctx->ccache);
 663     ctx->ccache = NULL;
 664 
 665     return ret;
 666 }
 667 
 668 
 669 static OM_uint32
 670 repl_mutual
 671 (OM_uint32 * minor_status,
 672  gsskrb5_ctx ctx,
 673  krb5_context context,
 674  const gss_OID mech_type,
 675  OM_uint32 req_flags,
 676  OM_uint32 time_req,
 677  const gss_channel_bindings_t input_chan_bindings,
 678  const gss_buffer_t input_token,
 679  gss_OID * actual_mech_type,
 680  gss_buffer_t output_token,
 681  OM_uint32 * ret_flags,
 682  OM_uint32 * time_rec
 683     )
 684 {
 685     OM_uint32 ret;
 686     krb5_error_code kret;
 687     krb5_data indata;
 688     krb5_ap_rep_enc_part *repl;
 689     int is_cfx = 0;
 690 
 691     output_token->length = 0;
 692     output_token->value = NULL;
 693 
 694     if (actual_mech_type)
 695         *actual_mech_type = GSS_KRB5_MECHANISM;
 696 
 697     if (ctx->flags & GSS_C_DCE_STYLE) {
 698         /* There is no OID wrapping. */
 699         indata.length   = input_token->length;
 700         indata.data     = input_token->value;
 701     } else {
 702         ret = _gsskrb5_decapsulate (minor_status,
 703                                     input_token,
 704                                     &indata,
 705                                     "\x02\x00",
 706                                     GSS_KRB5_MECHANISM);
 707         if (ret == GSS_S_DEFECTIVE_TOKEN) {
 708             /* check if there is an error token sent instead */
 709             ret = _gsskrb5_decapsulate (minor_status,
 710                                         input_token,
 711                                         &indata,
 712                                         "\x03\x00",
 713                                         GSS_KRB5_MECHANISM);
 714             if (ret == GSS_S_COMPLETE) {
 715                 KRB_ERROR error;
 716                 
 717                 kret = krb5_rd_error(context, &indata, &error);
 718                 if (kret == 0) {
 719                     kret = krb5_error_from_rd_error(context, &error, NULL);
 720 
 721                     /* save the time skrew for this host */
 722                     if (kret == KRB5KRB_AP_ERR_SKEW) {
 723                         krb5_data timedata;
 724                         unsigned char p[4];
 725                         int32_t t = error.stime - time(NULL);
 726 
 727                         p[0] = (t >> 24) & 0xFF;
 728                         p[1] = (t >> 16) & 0xFF;
 729                         p[2] = (t >> 8)  & 0xFF;
 730                         p[3] = (t >> 0)  & 0xFF;
 731 
 732                         timedata.data = p;
 733                         timedata.length = sizeof(p);
 734 
 735                         krb5_cc_set_config(context, ctx->ccache, ctx->target,
 736                                            "time-offset", &timedata);
 737 
 738                         if ((ctx->more_flags & RETRIED) == 0)
 739                             ctx->state = INITIATOR_RESTART;
 740                         ctx->more_flags |= RETRIED;
 741                     }
 742                     free_KRB_ERROR (&error);
 743                 }
 744                 *minor_status = kret;
 745                 return GSS_S_FAILURE;
 746             }
 747             return ret;
 748         }
 749     }
 750 
 751     kret = krb5_rd_rep (context,
 752                         ctx->auth_context,
 753                         &indata,
 754                         &repl);
 755     if (kret) {
 756         *minor_status = kret;
 757         return GSS_S_FAILURE;
 758     }
 759     krb5_free_ap_rep_enc_part (context,
 760                                repl);
 761 
 762     _gsskrb5i_is_cfx(ctx, &is_cfx);
 763     if (is_cfx) {
 764         krb5_keyblock *key = NULL;
 765 
 766         kret = krb5_auth_con_getremotesubkey(context,
 767                                              ctx->auth_context,
 768                                              &key);
 769         if (kret == 0 && key != NULL) {
 770             ctx->more_flags |= ACCEPTOR_SUBKEY;
 771             krb5_free_keyblock (context, key);
 772         }
 773     }
 774 
 775 
 776     *minor_status = 0;
 777     if (time_rec) {
 778         ret = _gsskrb5_lifetime_left(minor_status,
 779                                      context,
 780                                      ctx->lifetime,
 781                                      time_rec);
 782     } else {
 783         ret = GSS_S_COMPLETE;
 784     }
 785     if (ret_flags)
 786         *ret_flags = ctx->flags;
 787 
 788     if (req_flags & GSS_C_DCE_STYLE) {
 789         int32_t local_seq, remote_seq;
 790         krb5_data outbuf;
 791 
 792         /*
 793          * So DCE_STYLE is strange. The client echos the seq number
 794          * that the server used in the server's mk_rep in its own
 795          * mk_rep(). After when done, it resets to it's own seq number
 796          * for the gss_wrap calls.
 797          */
 798 
 799         krb5_auth_getremoteseqnumber(context, ctx->auth_context, &remote_seq);
 800         krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, &local_seq);
 801         krb5_auth_con_setlocalseqnumber(context, ctx->auth_context, remote_seq);
 802 
 803         kret = krb5_mk_rep(context, ctx->auth_context, &outbuf);
 804         if (kret) {
 805             *minor_status = kret;
 806             return GSS_S_FAILURE;
 807         }
 808         
 809         /* reset local seq number */
 810         krb5_auth_con_setlocalseqnumber(context, ctx->auth_context, local_seq); 
 811 
 812         output_token->length = outbuf.length;
 813         output_token->value  = outbuf.data;
 814     }
 815 
 816     return gsskrb5_initiator_ready(minor_status, ctx, context);
 817 }
 818 
 819 /*
 820  * gss_init_sec_context
 821  */
 822 
 823 OM_uint32 _gsskrb5_init_sec_context
 824 (OM_uint32 * minor_status,
 825  const gss_cred_id_t cred_handle,
 826  gss_ctx_id_t * context_handle,
 827  const gss_name_t target_name,
 828  const gss_OID mech_type,
 829  OM_uint32 req_flags,
 830  OM_uint32 time_req,
 831  const gss_channel_bindings_t input_chan_bindings,
 832  const gss_buffer_t input_token,
 833  gss_OID * actual_mech_type,
 834  gss_buffer_t output_token,
 835  OM_uint32 * ret_flags,
 836  OM_uint32 * time_rec
 837     )
 838 {
 839     krb5_context context;
 840     gsskrb5_cred cred = (gsskrb5_cred)cred_handle;
 841     gsskrb5_ctx ctx;
 842     OM_uint32 ret;
 843 
 844     GSSAPI_KRB5_INIT (&context);
 845 
 846     output_token->length = 0;
 847     output_token->value  = NULL;
 848 
 849     if (context_handle == NULL) {
 850         *minor_status = 0;
 851         return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;
 852     }
 853 
 854     if (ret_flags)
 855         *ret_flags = 0;
 856     if (time_rec)
 857         *time_rec = 0;
 858 
 859     if (target_name == GSS_C_NO_NAME) {
 860         if (actual_mech_type)
 861             *actual_mech_type = GSS_C_NO_OID;
 862         *minor_status = 0;
 863         return GSS_S_BAD_NAME;
 864     }
 865 
 866     if (mech_type != GSS_C_NO_OID &&
 867         !gss_oid_equal(mech_type, GSS_KRB5_MECHANISM))
 868         return GSS_S_BAD_MECH;
 869 
 870     if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) {
 871         OM_uint32 ret;
 872 
 873         if (*context_handle != GSS_C_NO_CONTEXT) {
 874             *minor_status = 0;
 875             return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;
 876         }
 877 
 878         ret = _gsskrb5_create_ctx(minor_status,
 879                                   context_handle,
 880                                   context,
 881                                   input_chan_bindings,
 882                                   INITIATOR_START);
 883         if (ret)
 884             return ret;
 885     }
 886 
 887     if (*context_handle == GSS_C_NO_CONTEXT) {
 888         *minor_status = 0;
 889         return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;
 890     }
 891 
 892     ctx = (gsskrb5_ctx) *context_handle;
 893 
 894     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
 895 
 896  again:
 897     switch (ctx->state) {
 898     case INITIATOR_START:
 899         ret = init_auth(minor_status,
 900                         cred,
 901                         ctx,
 902                         context,
 903                         target_name,
 904                         mech_type,
 905                         req_flags,
 906                         time_req,
 907                         input_token,
 908                         actual_mech_type,
 909                         output_token,
 910                         ret_flags,
 911                         time_rec);
 912         if (ret != GSS_S_COMPLETE)
 913             break;      
 914         /* FALL THOUGH */
 915     case INITIATOR_RESTART:
 916         ret = init_auth_restart(minor_status,
 917                                 cred,
 918                                 ctx,
 919                                 context,
 920                                 req_flags,
 921                                 input_chan_bindings,
 922                                 input_token,
 923                                 actual_mech_type,
 924                                 output_token,
 925                                 ret_flags,
 926                                 time_rec);
 927         break;
 928     case INITIATOR_WAIT_FOR_MUTAL:
 929         ret = repl_mutual(minor_status,
 930                           ctx,
 931                           context,
 932                           mech_type,
 933                           req_flags,
 934                           time_req,
 935                           input_chan_bindings,
 936                           input_token,
 937                           actual_mech_type,
 938                           output_token,
 939                           ret_flags,
 940                           time_rec);
 941         if (ctx->state == INITIATOR_RESTART)
 942             goto again;
 943         break;
 944     case INITIATOR_READY:
 945         /*
 946          * If we get there, the caller have called
 947          * gss_init_sec_context() one time too many.
 948          */
 949         _gsskrb5_set_status(EINVAL, "init_sec_context "
 950                             "called one time too many");
 951         *minor_status = EINVAL;
 952         ret = GSS_S_BAD_STATUS;
 953         break;
 954     default:
 955         _gsskrb5_set_status(EINVAL, "init_sec_context "
 956                             "invalid state %d for client",
 957                             (int)ctx->state);
 958         *minor_status = EINVAL;
 959         ret = GSS_S_BAD_STATUS;
 960         break;
 961     }
 962     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 963 
 964     /* destroy context in case of error */
 965     if (GSS_ERROR(ret)) {
 966         OM_uint32 min2;
 967         _gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER);
 968     }
 969 
 970     return ret;
 971 
 972 }

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