1 /*
   2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
   3  * Use is subject to license terms.
   4  */
   5 
   6 /*
   7  * Copyright 2000, 2004  by the Massachusetts Institute of Technology.
   8  * All Rights Reserved.
   9  *
  10  * Export of this software from the United States of America may
  11  *   require a specific license from the United States Government.
  12  *   It is the responsibility of any person or organization contemplating
  13  *   export to obtain such a license before exporting.
  14  * 
  15  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
  16  * distribute this software and its documentation for any purpose and
  17  * without fee is hereby granted, provided that the above copyright
  18  * notice appear in all copies and that both that copyright notice and
  19  * this permission notice appear in supporting documentation, and that
  20  * the name of M.I.T. not be used in advertising or publicity pertaining
  21  * to distribution of the software without specific, written prior
  22  * permission.  Furthermore if you modify this software you must label
  23  * your software as modified software and not distribute it in such a
  24  * fashion that it might be confused with the original M.I.T. software.
  25  * M.I.T. makes no representations about the suitability of
  26  * this software for any purpose.  It is provided "as is" without express
  27  * or implied warranty.
  28  * 
  29  */
  30 /*
  31  * Copyright 1993 by OpenVision Technologies, Inc.
  32  * 
  33  * Permission to use, copy, modify, distribute, and sell this software
  34  * and its documentation for any purpose is hereby granted without fee,
  35  * provided that the above copyright notice appears in all copies and
  36  * that both that copyright notice and this permission notice appear in
  37  * supporting documentation, and that the name of OpenVision not be used
  38  * in advertising or publicity pertaining to distribution of the software
  39  * without specific, written prior permission. OpenVision makes no
  40  * representations about the suitability of this software for any
  41  * purpose.  It is provided "as is" without express or implied warranty.
  42  * 
  43  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  44  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  45  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  46  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  47  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  48  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  49  * PERFORMANCE OF THIS SOFTWARE.
  50  */
  51 
  52 /*
  53  * Copyright (C) 1998 by the FundsXpress, INC.
  54  * 
  55  * All rights reserved.
  56  * 
  57  * Export of this software from the United States of America may require
  58  * a specific license from the United States Government.  It is the
  59  * responsibility of any person or organization contemplating export to
  60  * obtain such a license before exporting.
  61  * 
  62  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
  63  * distribute this software and its documentation for any purpose and
  64  * without fee is hereby granted, provided that the above copyright
  65  * notice appear in all copies and that both that copyright notice and
  66  * this permission notice appear in supporting documentation, and that
  67  * the name of FundsXpress. not be used in advertising or publicity pertaining
  68  * to distribution of the software without specific, written prior
  69  * permission.  FundsXpress makes no representations about the suitability of
  70  * this software for any purpose.  It is provided "as is" without express
  71  * or implied warranty.
  72  * 
  73  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  74  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  75  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  76  */
  77 
  78 #include "k5-int.h"
  79 #include "gssapiP_krb5.h"
  80 #ifdef HAVE_MEMORY_H
  81 #include <memory.h>
  82 #endif
  83 #include <assert.h>
  84 #include "auth_con.h"
  85 
  86 #ifdef CFX_EXERCISE
  87 #define CFX_ACCEPTOR_SUBKEY (time(0) & 1)
  88 #else
  89 #define CFX_ACCEPTOR_SUBKEY 1
  90 #endif
  91 
  92 /*
  93  * Decode, decrypt and store the forwarded creds in the local ccache.
  94  * and populate the callers delegated credential handle if it
  95  * was provided.
  96  */
  97 static krb5_error_code
  98 rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
  99     krb5_context context;
 100     krb5_auth_context auth_context;
 101     krb5_data *inbuf;
 102     krb5_gss_cred_id_t *out_cred;
 103 {
 104     krb5_creds ** creds = NULL;
 105     krb5_error_code retval;
 106     krb5_ccache ccache = NULL;
 107     krb5_gss_cred_id_t cred = NULL;
 108     krb5_auth_context new_auth_ctx = NULL;
 109         krb5_int32 flags_org;
 110 
 111     /* Solaris Kerberos */
 112     KRB5_LOG0(KRB5_INFO, "rd_and_store_for_creds() start");
 113 
 114         if ((retval = krb5_auth_con_getflags(context, auth_context, &flags_org)))
 115                 return retval;
 116         krb5_auth_con_setflags(context, auth_context,
 117                                0);
 118 
 119         /*
 120          * By the time krb5_rd_cred is called here (after krb5_rd_req has been
 121          * called in krb5_gss_accept_sec_context), the "keyblock" field of
 122          * auth_context contains a pointer to the session key, and the
 123          * "recv_subkey" field might contain a session subkey.  Either of
 124          * these (the "recv_subkey" if it isn't NULL, otherwise the
 125          * "keyblock") might have been used to encrypt the encrypted part of
 126          * the KRB_CRED message that contains the forwarded credentials.  (The
 127          * Java Crypto and Security Implementation from the DSTC in Australia
 128          * always uses the session key.  But apparently it never negotiates a
 129          * subkey, so this code works fine against a JCSI client.)  Up to the
 130          * present, though, GSSAPI clients linked against the MIT code (which
 131          * is almost all GSSAPI clients) don't encrypt the KRB_CRED message at
 132          * all -- at this level.  So if the first call to krb5_rd_cred fails,
 133          * we should call it a second time with another auth context freshly
 134          * created by krb5_auth_con_init.  All of its keyblock fields will be
 135          * NULL, so krb5_rd_cred will assume that the KRB_CRED message is
 136          * unencrypted.  (The MIT code doesn't actually send the KRB_CRED
 137          * message in the clear -- the "authenticator" whose "checksum" ends up
 138          * containing the KRB_CRED message does get encrypted.)
 139          */
 140     /* Solaris Kerberos */
 141     if ((retval = krb5_rd_cred(context, auth_context, inbuf, &creds, NULL))) {
 142         krb5_enctype enctype = ENCTYPE_NULL;
 143         /*
 144          * If the client is using non-DES enctypes it really ought to
 145          * send encrypted KRB-CREDs...
 146          */
 147         if (auth_context->keyblock != NULL)
 148             enctype = auth_context->keyblock->enctype;
 149         switch (enctype) {
 150         case ENCTYPE_DES_CBC_MD5:
 151         case ENCTYPE_DES_CBC_CRC:
 152         case ENCTYPE_DES3_CBC_SHA1:
 153             break;
 154         default:
 155             KRB5_LOG(KRB5_ERR, "rd_and_store_for_creds() error "
 156                     "krb5_rd_cred() retval = %d\n", retval);
 157             goto cleanup;
 158             /* NOTREACHED */
 159             break;
 160         }
 161 
 162         /* Try to krb5_rd_cred() likely unencrypted KRB-CRED */
 163                 if ((retval = krb5_auth_con_init(context, &new_auth_ctx)))
 164                         goto cleanup;
 165                 krb5_auth_con_setflags(context, new_auth_ctx, 0);
 166                 if ((retval = krb5_rd_cred(context, new_auth_ctx, inbuf,
 167                                            &creds, NULL))) {
 168                         /* Solaris Kerberos */
 169                         KRB5_LOG(KRB5_ERR, "rd_and_store_for_creds() error "
 170                             "krb5_rd_cred() retval = %d\n", retval);
 171                         goto cleanup;
 172                 }
 173     }
 174 
 175     if ((retval = krb5_cc_new_unique(context, "MEMORY", NULL, &ccache))) {
 176         ccache = NULL;
 177         goto cleanup;
 178     }
 179 
 180     if ((retval = krb5_cc_initialize(context, ccache, creds[0]->client))) {
 181         /* Solaris Kerberos */
 182         KRB5_LOG(KRB5_ERR, "rd_and_store_for_creds() error "
 183                 "krb5_cc_initialize() retval = %d\n", retval);
 184         goto cleanup;
 185     }
 186 
 187     if ((retval = krb5_cc_store_cred(context, ccache, creds[0]))) {
 188         /* Solaris Kerberos */
 189         KRB5_LOG(KRB5_ERR, "rd_and_store_for_creds() error "
 190                 "krb5_cc_store_cred() retval = %d\n", retval);
 191         goto cleanup;
 192     }
 193 
 194     /* generate a delegated credential handle */
 195     if (out_cred) {
 196         /* allocate memory for a cred_t... */
 197         if (!(cred =
 198               (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec)))) {
 199             retval = ENOMEM; /* out of memory? */
 200             *out_cred = NULL;
 201             goto cleanup;
 202         }
 203 
 204         /* zero it out... */
 205         /* Solaris Kerberos */
 206         (void) memset(cred, 0, sizeof(krb5_gss_cred_id_rec));
 207 
 208         retval = k5_mutex_init(&cred->lock);
 209         if (retval) {
 210             xfree(cred);
 211             cred = NULL;
 212             goto cleanup;
 213         }
 214 
 215         /* copy the client principle into it... */
 216         if ((retval =
 217              krb5_copy_principal(context, creds[0]->client, &(cred->princ)))) {
 218              /* Solaris Kerberos */
 219             KRB5_LOG(KRB5_ERR, "rd_and_store_for_creds() error "
 220                     "krb5_copy_principal() retval = %d\n", retval);
 221             k5_mutex_destroy(&cred->lock);
 222             retval = ENOMEM; /* out of memory? */
 223             xfree(cred); /* clean up memory on failure */
 224             cred = NULL;
 225             goto cleanup;
 226         }
 227 
 228         cred->usage = GSS_C_INITIATE; /* we can't accept with this */
 229         /* cred->princ already set */
 230         cred->prerfc_mech = 1; /* this cred will work with all three mechs */
 231         cred->rfc_mech = 1;
 232         cred->keytab = NULL; /* no keytab associated with this... */
 233         cred->tgt_expire = creds[0]->times.endtime; /* store the end time */
 234         cred->ccache = ccache; /* the ccache containing the credential */
 235         ccache = NULL; /* cred takes ownership so don't destroy */
 236     }
 237 
 238     /* If there were errors, there might have been a memory leak
 239        if (!cred)
 240        if ((retval = krb5_cc_close(context, ccache)))
 241        goto cleanup;
 242     */
 243 cleanup:
 244     if (creds)
 245         krb5_free_tgt_creds(context, creds);
 246 
 247     if (ccache)
 248         (void)krb5_cc_destroy(context, ccache);
 249 
 250     if (out_cred)
 251         *out_cred = cred; /* return credential */
 252 
 253     if (new_auth_ctx)
 254         krb5_auth_con_free(context, new_auth_ctx);
 255 
 256     krb5_auth_con_setflags(context, auth_context, flags_org);
 257 
 258     /* Solaris Kerberos */
 259     KRB5_LOG(KRB5_INFO, "rd_and_store_for_creds() end retval %d", retval);
 260     return retval;
 261 }
 262 
 263 /*
 264  * SUNW15resync
 265  * Most of the logic here left "as is" because of lots of fixes MIT
 266  * does not have yet
 267  */
 268 OM_uint32
 269 krb5_gss_accept_sec_context(minor_status, context_handle, 
 270                             verifier_cred_handle, input_token,
 271                             input_chan_bindings, src_name, mech_type,
 272                             output_token, ret_flags, time_rec,
 273                             delegated_cred_handle)
 274      OM_uint32 *minor_status;
 275      gss_ctx_id_t *context_handle;
 276      gss_cred_id_t verifier_cred_handle;
 277      gss_buffer_t input_token;
 278      gss_channel_bindings_t input_chan_bindings;
 279      gss_name_t *src_name;
 280      gss_OID *mech_type;
 281      gss_buffer_t output_token;
 282      OM_uint32 *ret_flags;
 283      OM_uint32 *time_rec;
 284      gss_cred_id_t *delegated_cred_handle;
 285 {
 286    krb5_context context;
 287    unsigned char *ptr, *ptr2;
 288    char *sptr;
 289    long tmp;
 290    size_t md5len;
 291    int bigend;
 292    krb5_gss_cred_id_t cred = 0;
 293    krb5_data ap_rep, ap_req;
 294    krb5_ap_req *request = NULL;
 295    int i;
 296    krb5_error_code code;
 297    krb5_address addr, *paddr;
 298    krb5_authenticator *authdat = 0;
 299    krb5_checksum reqcksum;
 300    krb5_principal name = NULL;
 301    krb5_ui_4 gss_flags = 0;
 302    krb5_gss_ctx_id_rec *ctx = 0;
 303    krb5_timestamp now;
 304    gss_buffer_desc token;
 305    krb5_auth_context auth_context = NULL;
 306    krb5_ticket * ticket = NULL;
 307    int option_id;
 308    krb5_data option;
 309    const gss_OID_desc *mech_used = NULL;
 310    OM_uint32 major_status = GSS_S_FAILURE;
 311    krb5_error krb_error_data;
 312    krb5_data scratch;
 313    gss_cred_id_t cred_handle = NULL;
 314    krb5_gss_cred_id_t deleg_cred = NULL;
 315    OM_uint32 saved_ap_options = 0;
 316    krb5int_access kaccess;
 317    int cred_rcache = 0;
 318    OM_uint32 t_minor_status = 0;
 319 
 320    KRB5_LOG0(KRB5_INFO,"krb5_gss_accept_sec_context() start");
 321 
 322    code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
 323    if (code) {
 324        *minor_status = code;
 325        return(GSS_S_FAILURE);
 326    }
 327 
 328    code = krb5_gss_init_context(&context);
 329    if (code) {
 330        *minor_status = code;
 331        return GSS_S_FAILURE;
 332    }
 333 
 334    /* set up returns to be freeable */
 335 
 336    if (src_name)
 337       *src_name = (gss_name_t) NULL;
 338    output_token->length = 0;
 339    output_token->value = NULL;
 340    token.value = 0;
 341    reqcksum.contents = 0;
 342    ap_req.data = 0;
 343    ap_rep.data = 0;
 344    
 345    if (mech_type)
 346       *mech_type = GSS_C_NULL_OID;
 347    /* initialize the delegated cred handle to NO_CREDENTIAL for now */
 348    if (delegated_cred_handle)
 349       *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
 350 
 351    /*
 352     * Context handle must be unspecified.  Actually, it must be
 353     * non-established, but currently, accept_sec_context never returns
 354     * a non-established context handle.
 355     */
 356    /*SUPPRESS 29*/
 357    if (*context_handle != GSS_C_NO_CONTEXT) {
 358       *minor_status = 0;
 359 
 360        /* Solaris kerberos: the original Solaris code returned GSS_S_NO_CONTEXT
 361         * for this error.  This conflicts somewhat with RFC2743 which states
 362         * GSS_S_NO_CONTEXT should be returned only for sucessor calls following
 363         * GSS_S_CONTINUE_NEEDED status returns.  Note the MIT code doesn't
 364         * return GSS_S_NO_CONTEXT at all.
 365         */
 366 
 367       major_status = GSS_S_NO_CONTEXT;
 368       KRB5_LOG0(KRB5_ERR,"krb5_gss_accept_sec_context() "
 369               "error GSS_S_NO_CONTEXT");
 370       goto cleanup;
 371    }
 372 
 373    /* verify the token's integrity, and leave the token in ap_req.
 374       figure out which mech oid was used, and save it */
 375 
 376    ptr = (unsigned char *) input_token->value;
 377 
 378    if (!(code = g_verify_token_header(gss_mech_krb5,
 379                                       (uint32_t *)&(ap_req.length),
 380                                       &ptr, KG_TOK_CTX_AP_REQ,
 381                                       input_token->length, 1))) {
 382        mech_used = gss_mech_krb5;
 383    } else if ((code == G_WRONG_MECH) &&
 384               !(code = g_verify_token_header(gss_mech_krb5_old,
 385                                              (uint32_t *)&(ap_req.length),
 386                                              &ptr, KG_TOK_CTX_AP_REQ,
 387                                              input_token->length, 1))) {
 388        /*
 389         * Previous versions of this library used the old mech_id
 390         * and some broken behavior (wrong IV on checksum
 391         * encryption).  We support the old mech_id for
 392         * compatibility, and use it to decide when to use the
 393         * old behavior.
 394         */
 395        mech_used = gss_mech_krb5_old;
 396    } else {
 397        major_status = GSS_S_DEFECTIVE_TOKEN;
 398        goto fail;
 399    }
 400 
 401    sptr = (char *) ptr;
 402    TREAD_STR(sptr, ap_req.data, ap_req.length);
 403 
 404    /*
 405     * Solaris Kerberos: 
 406     *  We need to decode the request now so that we can get the
 407     *  service principal in order to try and acquire a cred for it.
 408     *  below in the "handle default cred handle" code block.
 409     */
 410    if (!krb5_is_ap_req(&ap_req)) {
 411        code = KRB5KRB_AP_ERR_MSG_TYPE;
 412        goto fail;
 413    }
 414    /* decode the AP-REQ into request */
 415    if ((code = decode_krb5_ap_req(&ap_req, &request))) {
 416        if (code == KRB5_BADMSGTYPE)
 417            code = KRB5KRB_AP_ERR_BADVERSION;
 418        goto fail;
 419    }
 420 
 421    /* handle default cred handle */
 422    /* 
 423     * Solaris Kerberos:
 424     * If there is no princ associated with the cred then treat it the
 425     * the same as GSS_C_NO_CREDENTIAL. 
 426     */
 427    if (verifier_cred_handle == GSS_C_NO_CREDENTIAL ||
 428     ((krb5_gss_cred_id_t)verifier_cred_handle)->princ == NULL) {
 429        /* Note that we try to acquire a cred for the service principal
 430         * named in the AP-REQ. This allows us to implement option (ii)
 431         * of the recommended behaviour for GSS_Accept_sec_context() as
 432         * described in section 1.1.1.3 of RFC2743.
 433 
 434         * This is far more useful that option (i), for which we would
 435         * acquire a cred for GSS_C_NO_NAME.
 436         */
 437        /* copy the princ from the ap-req or we'll lose it when we free
 438           the ap-req */
 439        krb5_principal princ;
 440        if ((code = krb5_copy_principal(context, request->ticket->server,
 441                                        &princ))) {
 442            KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
 443                     "krb5_copy_principal() error code %d", code);
 444            major_status = GSS_S_FAILURE;
 445            goto fail;
 446        }
 447        /* intern the acceptor name */
 448        if (! kg_save_name((gss_name_t) princ)) {
 449            code = G_VALIDATE_FAILED;
 450            major_status = GSS_S_FAILURE;
 451            goto fail;
 452        }
 453        major_status = krb5_gss_acquire_cred((OM_uint32*) &code,
 454                                             (gss_name_t) princ,
 455                                             GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
 456                                             GSS_C_ACCEPT, &cred_handle,
 457                                             NULL, NULL);
 458 
 459        if (major_status != GSS_S_COMPLETE){
 460 
 461            /* Solaris kerberos: RFC2743 indicate this should be returned if we
 462             * can't aquire a default cred.
 463             */
 464            KRB5_LOG(KRB5_ERR,"krb5_gss_accept_sec_context() "
 465                   "krb5_gss_acquire_cred() error"
 466                    "orig major_status = %d, now = GSS_S_NO_CRED\n",
 467                    major_status);
 468 
 469            major_status = GSS_S_NO_CRED;
 470            goto fail;
 471        }
 472 
 473    } else {
 474        cred_handle = verifier_cred_handle;
 475    }
 476 
 477    major_status = krb5_gss_validate_cred((OM_uint32*) &code,
 478                                                  cred_handle);
 479 
 480    if (GSS_ERROR(major_status)){
 481 
 482        /* Solaris kerberos: RFC2743 indicate GSS_S_NO_CRED should be returned if
 483         * the supplied cred isn't valid.
 484         */
 485 
 486        KRB5_LOG(KRB5_ERR,"krb5_gss_accept_sec_context() "
 487               "krb5_gss_validate_cred() error"
 488                "orig major_status = %d, now = GSS_S_NO_CRED\n",
 489                major_status);
 490 
 491        major_status = GSS_S_NO_CRED;
 492        goto fail;
 493    }
 494 
 495    cred = (krb5_gss_cred_id_t) cred_handle;
 496 
 497    /* make sure the supplied credentials are valid for accept */
 498 
 499    if ((cred->usage != GSS_C_ACCEPT) &&
 500        (cred->usage != GSS_C_BOTH)) {
 501        code = 0;
 502       KRB5_LOG0(KRB5_ERR,"krb5_gss_accept_sec_context() "
 503               "error GSS_S_NO_CONTEXT");
 504        major_status = GSS_S_NO_CRED;
 505        goto fail;
 506    }
 507 
 508    /* construct the sender_addr */
 509 
 510    if ((input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) &&
 511        (input_chan_bindings->initiator_addrtype == GSS_C_AF_INET)) {
 512        /* XXX is this right? */
 513        addr.addrtype = ADDRTYPE_INET;
 514        addr.length = input_chan_bindings->initiator_address.length;
 515        addr.contents = input_chan_bindings->initiator_address.value;
 516 
 517        paddr = &addr;
 518    } else {
 519        paddr = NULL;
 520    }
 521 
 522    /* verify the AP_REQ message - setup the auth_context and rcache */
 523 
 524    if ((code = krb5_auth_con_init(context, &auth_context))) {
 525        major_status = GSS_S_FAILURE;
 526        /* Solaris Kerberos */
 527        KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
 528               "krb5_auth_con_init() error code %d", code);
 529        goto fail;
 530    }
 531 
 532    (void) krb5_auth_con_setflags(context, auth_context,
 533                           KRB5_AUTH_CONTEXT_DO_SEQUENCE);
 534 
 535    if (cred->rcache) {
 536        cred_rcache = 1;
 537        if ((code = krb5_auth_con_setrcache(context, auth_context, cred->rcache))) {
 538            major_status = GSS_S_FAILURE;
 539            /* Solaris Kerberos */
 540            KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
 541                     "krb5_auth_con_setrcache() error code %d", code);
 542            goto fail;
 543        }
 544    }
 545    if ((code = krb5_auth_con_setaddrs(context, auth_context, NULL, paddr))) {
 546        major_status = GSS_S_FAILURE;
 547        /* Solaris Kerberos */
 548        KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
 549               "krb5_auth_con_setaddrs() error code %d", code);
 550        goto fail;
 551    }
 552 
 553    if ((code = krb5_rd_req_decoded(context, &auth_context, request,
 554                            cred->princ, cred->keytab, NULL, &ticket))) {
 555        KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
 556               "krb5_rd_req() error code %d", code);
 557        if (code == KRB5_KT_KVNONOTFOUND || code == KRB5_KT_NOTFOUND) {
 558            major_status = GSS_S_DEFECTIVE_CREDENTIAL;
 559            code = KRB5KRB_AP_ERR_NOKEY;
 560        }
 561        else if (code == KRB5KRB_AP_WRONG_PRINC) {
 562            major_status = GSS_S_NO_CRED;
 563            code = KRB5KRB_AP_ERR_NOT_US;
 564        }
 565        else if (code == KRB5KRB_AP_ERR_REPEAT)
 566            major_status = GSS_S_DUPLICATE_TOKEN;
 567        else
 568            major_status = GSS_S_FAILURE;
 569        goto fail;
 570    }
 571    krb5_auth_con_setflags(context, auth_context,
 572                           KRB5_AUTH_CONTEXT_DO_SEQUENCE);
 573 
 574    krb5_auth_con_getauthenticator(context, auth_context, &authdat);
 575 
 576 #if 0
 577    /* make sure the necessary parts of the authdat are present */
 578 
 579    if ((authdat->authenticator->subkey == NULL) ||
 580        (authdat->ticket->enc_part2 == NULL)) {
 581            code = KG_NO_SUBKEY;
 582            major_status = GSS_S_FAILURE;
 583            goto fail;
 584    }
 585 #endif
 586 
 587    {
 588        /* gss krb5 v1 */
 589 
 590        /* stash this now, for later. */
 591        code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &md5len);
 592        if (code) {
 593            /* Solaris Kerberos */
 594            KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
 595                   "krb5_c_checksum_length() error code %d", code);
 596            major_status = GSS_S_FAILURE;
 597            goto fail;
 598        }
 599 
 600        /* verify that the checksum is correct */
 601 
 602        /*
 603          The checksum may be either exactly 24 bytes, in which case
 604          no options are specified, or greater than 24 bytes, in which case
 605          one or more options are specified. Currently, the only valid
 606          option is KRB5_GSS_FOR_CREDS_OPTION ( = 1 ).
 607        */
 608 
 609        if ((authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) ||
 610            (authdat->checksum->length < 24)) {
 611            code = 0;
 612            major_status = GSS_S_BAD_BINDINGS;
 613            goto fail;
 614        }
 615 
 616        /*
 617          "Be liberal in what you accept, and
 618          conservative in what you send"
 619          -- rfc1123
 620 
 621          This code will let this acceptor interoperate with an initiator
 622          using little-endian or big-endian integer encoding.
 623        */
 624 
 625        ptr = (unsigned char *) authdat->checksum->contents;
 626        bigend = 0;
 627 
 628        TREAD_INT(ptr, tmp, bigend);
 629 
 630        if (tmp != md5len) {
 631            ptr = (unsigned char *) authdat->checksum->contents;
 632            bigend = 1;
 633 
 634            TREAD_INT(ptr, tmp, bigend);
 635 
 636            if (tmp != md5len) {
 637                code = KG_BAD_LENGTH;
 638                major_status = GSS_S_FAILURE;
 639                goto fail;
 640            }
 641        }
 642 
 643        /* at this point, bigend is set according to the initiator's
 644           byte order */
 645 
 646 
 647        /* 
 648           The following section of code attempts to implement the
 649           optional channel binding facility as described in RFC2743.
 650 
 651           Since this facility is optional channel binding may or may
 652           not have been provided by either the client or the server.
 653 
 654           If the server has specified input_chan_bindings equal to
 655           GSS_C_NO_CHANNEL_BINDINGS then we skip the check.  If
 656           the server does provide channel bindings then we compute
 657           a checksum and compare against those provided by the
 658           client.  If the check fails we test the clients checksum
 659           to see whether the client specified GSS_C_NO_CHANNEL_BINDINGS.
 660           If either test succeeds we continue without error.
 661         */
 662        if ((code = kg_checksum_channel_bindings(context, 
 663                                                 input_chan_bindings,
 664                                                 &reqcksum, bigend))) {
 665            /* Solaris Kerberos */
 666            KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
 667                   "kg_checksum_channel_bindings() error code %d", code);
 668          major_status = GSS_S_BAD_BINDINGS;
 669          goto fail;
 670        }
 671 
 672        TREAD_STR(ptr, ptr2, reqcksum.length);
 673 
 674        if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS ) {
 675            if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
 676                xfree(reqcksum.contents);
 677                reqcksum.contents = 0;
 678                 if ((code = kg_checksum_channel_bindings(context,
 679                                                   GSS_C_NO_CHANNEL_BINDINGS,
 680                                                   &reqcksum, bigend))) {
 681                    major_status = GSS_S_BAD_BINDINGS;
 682                    goto fail;
 683                 }
 684                if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
 685                    code = 0;
 686                    major_status = GSS_S_BAD_BINDINGS;
 687                    goto fail;
 688                 }
 689            }
 690            
 691        }
 692 
 693        TREAD_INT(ptr, gss_flags, bigend);
 694 
 695        /* if the checksum length > 24, there are options to process */
 696 
 697        if(authdat->checksum->length > 24 && (gss_flags & GSS_C_DELEG_FLAG)) {
 698 
 699            i = authdat->checksum->length - 24;
 700 
 701            if (i >= 4) {
 702 
 703                TREAD_INT16(ptr, option_id, bigend);
 704 
 705                TREAD_INT16(ptr, option.length, bigend);
 706 
 707                i -= 4;
 708 
 709                if (i < option.length || option.length < 0) {
 710                    code = KG_BAD_LENGTH;
 711                    major_status = GSS_S_FAILURE;
 712                    goto fail;
 713                }
 714 
 715                /* have to use ptr2, since option.data is wrong type and
 716                   macro uses ptr as both lvalue and rvalue */
 717 
 718                TREAD_STR(ptr, ptr2, option.length);
 719                option.data = (char *) ptr2;
 720 
 721                i -= option.length;
 722 
 723                if (option_id != KRB5_GSS_FOR_CREDS_OPTION) {
 724                    major_status = GSS_S_FAILURE;
 725                    goto fail;
 726                }
 727 
 728                    /* store the delegated credential */
 729 
 730                    code = rd_and_store_for_creds(context, auth_context, &option,
 731                                                  (delegated_cred_handle) ?
 732                                                  &deleg_cred : NULL);
 733                    if (code) {
 734                        major_status = GSS_S_FAILURE;
 735                        goto fail;
 736                    }
 737 
 738            } /* if i >= 4 */
 739            /* ignore any additional trailing data, for now */
 740 #ifdef CFX_EXERCISE
 741            {
 742                FILE *f = fopen("/tmp/gsslog", "a");
 743                if (f) {
 744                    fprintf(f,
 745                            "initial context token with delegation, %d extra bytes\n",
 746                            i);
 747                    fclose(f);
 748                }
 749            }
 750 #endif
 751        } else {
 752 #ifdef CFX_EXERCISE
 753            {
 754                FILE *f = fopen("/tmp/gsslog", "a");
 755                if (f) {
 756                    if (gss_flags & GSS_C_DELEG_FLAG)
 757                        fprintf(f,
 758                                "initial context token, delegation flag but too small\n");
 759                    else
 760                        /* no deleg flag, length might still be too big */
 761                        fprintf(f,
 762                                "initial context token, %d extra bytes\n",
 763                                authdat->checksum->length - 24);
 764                    fclose(f);
 765                }
 766            }
 767 #endif
 768        }
 769    }
 770 
 771    /* create the ctx struct and start filling it in */
 772 
 773    if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
 774        == NULL) {
 775        code = ENOMEM;
 776        major_status = GSS_S_FAILURE;
 777        goto fail;
 778    }
 779 
 780    memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
 781    ctx->mech_used = (gss_OID) mech_used;
 782    ctx->auth_context = auth_context;
 783    ctx->initiate = 0;
 784    ctx->gss_flags = (GSS_C_TRANS_FLAG |
 785                     ((gss_flags) & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |
 786                             GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
 787                             GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG)));
 788    ctx->seed_init = 0;
 789    ctx->big_endian = bigend;
 790    ctx->cred_rcache = cred_rcache;
 791 
 792    /* Intern the ctx pointer so that delete_sec_context works */
 793    if (! kg_save_ctx_id((gss_ctx_id_t) ctx)) {
 794        xfree(ctx);
 795        ctx = 0;
 796 
 797         /* Solaris Kerberos */
 798        KRB5_LOG0(KRB5_ERR, "krb5_gss_accept_sec_context() "
 799               "kg_save_ctx_id() error");
 800        code = G_VALIDATE_FAILED;
 801        major_status = GSS_S_FAILURE;
 802        goto fail;
 803    }
 804 
 805    if ((code = krb5_copy_principal(context, cred->princ, &ctx->here))) {
 806         /* Solaris Kerberos */
 807        KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
 808               "krb5_copy_principal() error code %d", code);
 809        major_status = GSS_S_FAILURE;
 810        goto fail;
 811    }
 812 
 813    if ((code = krb5_copy_principal(context, authdat->client, &ctx->there))) {
 814         /* Solaris Kerberos */
 815        KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
 816               "krb5_copy_principal() 2 error code %d", code);
 817        major_status = GSS_S_FAILURE;
 818        goto fail;
 819    }
 820 
 821    if ((code = krb5_auth_con_getrecvsubkey(context, auth_context,
 822                                            &ctx->subkey))) { 
 823         /* Solaris Kerberos */
 824        KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
 825               "krb5_auth_con_getremotesubkey() error code %d", code);
 826        major_status = GSS_S_FAILURE;      
 827        goto fail;
 828    }
 829 
 830    /* use the session key if the subkey isn't present */
 831 
 832    if (ctx->subkey == NULL) {
 833        if ((code = krb5_auth_con_getkey(context, auth_context,
 834                                         &ctx->subkey))) {
 835         /* Solaris Kerberos */
 836            KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
 837                       "krb5_auth_con_getkey() error code %d", code);
 838            *minor_status = (OM_uint32) KRB5KDC_ERR_NULL_KEY;
 839            major_status = GSS_S_FAILURE;
 840            goto fail;
 841        }
 842    }
 843 
 844    if (ctx->subkey == NULL) {
 845        /* this isn't a very good error, but it's not clear to me this
 846           can actually happen */
 847        major_status = GSS_S_FAILURE;
 848        code = KRB5KDC_ERR_NULL_KEY;
 849        goto fail;
 850    }
 851 
 852     /* Solaris Kerberos */
 853    KRB5_LOG(KRB5_ERR,"krb5_gss_accept_sec_context() "
 854            "ctx->subkey->enctype=%d", ctx->subkey->enctype);
 855 
 856    ctx->proto = 0;
 857    switch(ctx->subkey->enctype) {
 858    case ENCTYPE_DES_CBC_MD5:
 859    case ENCTYPE_DES_CBC_CRC:
 860        ctx->subkey->enctype = ENCTYPE_DES_CBC_RAW;
 861        ctx->signalg = SGN_ALG_DES_MAC_MD5;
 862        ctx->cksum_size = 8;
 863        ctx->sealalg = SEAL_ALG_DES;
 864 
 865        /* fill in the encryption descriptors */
 866 
 867        if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) {
 868            major_status = GSS_S_FAILURE;
 869            goto fail;
 870        }
 871 
 872        for (i=0; i<ctx->enc->length; i++)
 873            /*SUPPRESS 113*/
 874            ctx->enc->contents[i] ^= 0xf0;
 875 
 876        goto copy_subkey_to_seq;
 877        break;
 878 
 879    case ENCTYPE_DES3_CBC_SHA1:
 880        ctx->subkey->enctype = ENCTYPE_DES3_CBC_RAW;
 881        ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD;
 882        ctx->cksum_size = 20;
 883        ctx->sealalg = SEAL_ALG_DES3KD;
 884 
 885        /* fill in the encryption descriptors */
 886    copy_subkey:
 887        if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) {
 888            major_status = GSS_S_FAILURE;
 889            goto fail;
 890        }
 891    copy_subkey_to_seq:
 892        if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq))) {
 893            major_status = GSS_S_FAILURE;
 894            goto fail;
 895        }
 896        break;
 897 
 898    case ENCTYPE_ARCFOUR_HMAC:
 899        ctx->signalg = SGN_ALG_HMAC_MD5 ;
 900        ctx->cksum_size = 8;
 901        ctx->sealalg = SEAL_ALG_MICROSOFT_RC4 ;
 902        goto copy_subkey;
 903 
 904    default:
 905        ctx->signalg = -1;
 906        ctx->sealalg = -1;
 907        ctx->proto = 1;
 908        code = (*kaccess.krb5int_c_mandatory_cksumtype)(context, ctx->subkey->enctype,
 909                                             &ctx->cksumtype);
 910        if (code)
 911            goto fail;
 912        code = krb5_c_checksum_length(context, ctx->cksumtype,
 913                 (size_t *)&ctx->cksum_size);
 914        if (code)
 915            goto fail;
 916        ctx->have_acceptor_subkey = 0;
 917        goto copy_subkey;
 918    }
 919 
 920     /* Solaris Kerberos */
 921    KRB5_LOG1(KRB5_ERR, "accept_sec_context:  subkey enctype = %d proto = %d",
 922         ctx->subkey->enctype, ctx->proto);
 923 
 924    ctx->endtime = ticket->enc_part2->times.endtime;
 925    ctx->krb_flags = ticket->enc_part2->flags;
 926 
 927    krb5_free_ticket(context, ticket); /* Done with ticket */
 928 
 929    {
 930        krb5_ui_4 seq_temp;
 931        krb5_auth_con_getremoteseqnumber(context, auth_context,
 932                 (krb5_int32 *)&seq_temp);
 933        ctx->seq_recv = seq_temp;
 934    }
 935 
 936    if ((code = krb5_timeofday(context, &now))) {
 937        major_status = GSS_S_FAILURE;
 938        goto fail;
 939    }
 940 
 941    if (ctx->endtime < now) {
 942        code = 0;
 943        major_status = GSS_S_CREDENTIALS_EXPIRED;
 944        goto fail;
 945    }
 946 
 947    g_order_init(&(ctx->seqstate), ctx->seq_recv,
 948                 (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
 949                 (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0, ctx->proto);
 950 
 951    /* at this point, the entire context structure is filled in, 
 952       so it can be released.  */
 953 
 954    /* generate an AP_REP if necessary */
 955 
 956    if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
 957        unsigned char * ptr3;
 958        krb5_ui_4 seq_temp;
 959        int cfx_generate_subkey;
 960 
 961        if (ctx->proto == 1)
 962            cfx_generate_subkey = CFX_ACCEPTOR_SUBKEY;
 963        else
 964            cfx_generate_subkey = 0;
 965 
 966        if (cfx_generate_subkey) {
 967            krb5_int32 acflags;
 968            code = krb5_auth_con_getflags(context, auth_context, &acflags);
 969            if (code == 0) {
 970                acflags |= KRB5_AUTH_CONTEXT_USE_SUBKEY;
 971                code = krb5_auth_con_setflags(context, auth_context, acflags);
 972            }
 973            if (code) {
 974                major_status = GSS_S_FAILURE;
 975                goto fail;
 976            }
 977        }
 978 
 979        if ((code = krb5_mk_rep(context, auth_context, &ap_rep))) {
 980            major_status = GSS_S_FAILURE;
 981            goto fail;
 982        }
 983 
 984        krb5_auth_con_getlocalseqnumber(context, auth_context,
 985                 (krb5_int32 *)&seq_temp);
 986        ctx->seq_send = seq_temp & 0xffffffffL;
 987 
 988        if (cfx_generate_subkey) {
 989            /* Get the new acceptor subkey.  With the code above, there
 990               should always be one if we make it to this point.  */
 991            code = krb5_auth_con_getsendsubkey(context, auth_context,
 992                                               &ctx->acceptor_subkey);
 993            if (code != 0) {
 994                major_status = GSS_S_FAILURE;
 995                goto fail;
 996            }
 997            code = (*kaccess.krb5int_c_mandatory_cksumtype)(context,
 998                                                 ctx->acceptor_subkey->enctype,
 999                                                 &ctx->acceptor_subkey_cksumtype);
1000            if (code) {
1001                major_status = GSS_S_FAILURE;
1002                goto fail;
1003            }
1004            ctx->have_acceptor_subkey = 1;
1005        }
1006 
1007        /* the reply token hasn't been sent yet, but that's ok. */
1008        ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
1009        ctx->established = 1;
1010 
1011        token.length = g_token_size(mech_used, ap_rep.length);
1012 
1013        if ((token.value = (unsigned char *) xmalloc(token.length))
1014            == NULL) {
1015            major_status = GSS_S_FAILURE;
1016            code = ENOMEM;
1017            goto fail;
1018        }
1019        ptr3 = token.value;
1020        g_make_token_header(mech_used, ap_rep.length,
1021                            &ptr3, KG_TOK_CTX_AP_REP);
1022 
1023        TWRITE_STR(ptr3, ap_rep.data, ap_rep.length);
1024 
1025        ctx->established = 1;
1026 
1027    } else {
1028        token.length = 0;
1029        token.value = NULL;
1030        ctx->seq_send = ctx->seq_recv;
1031 
1032        ctx->established = 1;
1033    }
1034 
1035    /* set the return arguments */
1036 
1037    if (src_name) {
1038        if ((code = krb5_copy_principal(context, ctx->there, &name))) {
1039            major_status = GSS_S_FAILURE;
1040            goto fail;
1041        }
1042        /* intern the src_name */
1043        if (! kg_save_name((gss_name_t) name)) {
1044            code = G_VALIDATE_FAILED;
1045            major_status = GSS_S_FAILURE;
1046            goto fail;
1047        }
1048    }
1049 
1050    if (mech_type)
1051       *mech_type = (gss_OID) mech_used;
1052 
1053    if (time_rec)
1054       *time_rec = ctx->endtime - now;
1055 
1056    if (ret_flags)
1057       *ret_flags = ctx->gss_flags;
1058 
1059    *context_handle = (gss_ctx_id_t)ctx;
1060    *output_token = token;
1061 
1062    if (src_name)
1063       *src_name = (gss_name_t) name;
1064 
1065    if (delegated_cred_handle && deleg_cred) {
1066        if (!kg_save_cred_id((gss_cred_id_t) deleg_cred)) {
1067            /* Solaris Kerberos */
1068            KRB5_LOG0(KRB5_ERR, "krb5_gss_accept_sec_context() "
1069                       "kg_save_cred_id() error");
1070            major_status = GSS_S_FAILURE;
1071            code = (OM_uint32) G_VALIDATE_FAILED;
1072            goto fail;
1073        }
1074 
1075        *delegated_cred_handle = (gss_cred_id_t) deleg_cred;
1076    }
1077 
1078    /* finally! */
1079 
1080    *minor_status = 0;
1081    major_status = GSS_S_COMPLETE;
1082 
1083  fail:
1084    if (authdat)
1085        krb5_free_authenticator(context, authdat);
1086    /* The ctx structure has the handle of the auth_context */
1087    if (auth_context && !ctx) {
1088        if (cred_rcache)
1089            (void)krb5_auth_con_setrcache(context, auth_context, NULL);
1090 
1091        krb5_auth_con_free(context, auth_context);
1092    }
1093    if (reqcksum.contents)
1094        xfree(reqcksum.contents);
1095    if (ap_rep.data)
1096        xfree(ap_rep.data);
1097 
1098    if (request != NULL) {
1099         saved_ap_options = request->ap_options;
1100         krb5_free_ap_req(context, request);
1101         request = NULL;
1102    }
1103 
1104    if (!GSS_ERROR(major_status) && major_status != GSS_S_CONTINUE_NEEDED) {
1105         if (!verifier_cred_handle && cred_handle) {
1106                 krb5_gss_release_cred(minor_status, &cred_handle);
1107         }
1108 
1109         if (ctx)
1110             ctx->k5_context = context;
1111 
1112         return(major_status);
1113    }
1114 
1115    /* from here on is the real "fail" code */
1116 
1117    if (ctx)
1118        (void) krb5_gss_delete_sec_context(minor_status, 
1119                                           (gss_ctx_id_t *) &ctx, NULL);
1120    if (deleg_cred) { /* free memory associated with the deleg credential */
1121        if (deleg_cred->ccache)
1122            (void)krb5_cc_close(context, deleg_cred->ccache);
1123        if (deleg_cred->princ)
1124            krb5_free_principal(context, deleg_cred->princ);
1125        xfree(deleg_cred);
1126    }
1127    if (token.value)
1128        xfree(token.value);
1129    if (name) {
1130        (void) kg_delete_name((gss_name_t) name);
1131        krb5_free_principal(context, name);
1132    }
1133 
1134    *minor_status = code;
1135 
1136    if (saved_ap_options & AP_OPTS_MUTUAL_REQUIRED)
1137         gss_flags |= GSS_C_MUTUAL_FLAG;
1138 
1139    if (cred
1140        && ((gss_flags & GSS_C_MUTUAL_FLAG)
1141            || (major_status == GSS_S_CONTINUE_NEEDED))) {
1142        unsigned int tmsglen;
1143        int toktype;
1144 
1145        /*
1146         * The client is expecting a response, so we can send an
1147         * error token back
1148         */
1149        memset(&krb_error_data, 0, sizeof(krb_error_data));
1150 
1151        code -= ERROR_TABLE_BASE_krb5;
1152        if (code < 0 || code > 128)
1153            code = 60 /* KRB_ERR_GENERIC */;
1154 
1155        krb_error_data.error = code;
1156        (void) krb5_us_timeofday(context, &krb_error_data.stime,
1157                                 &krb_error_data.susec);
1158        krb_error_data.server = cred->princ;
1159 
1160        code = krb5_mk_error(context, &krb_error_data, &scratch);
1161        if (code)
1162            goto cleanup;
1163 
1164        tmsglen = scratch.length;
1165        toktype = KG_TOK_CTX_ERROR;
1166 
1167        token.length = g_token_size(mech_used, tmsglen);
1168        token.value = (unsigned char *) xmalloc(token.length);
1169        if (!token.value)
1170           goto cleanup;
1171 
1172        ptr = token.value;
1173        g_make_token_header(mech_used, tmsglen, &ptr, toktype);
1174 
1175        TWRITE_STR(ptr, scratch.data, scratch.length);
1176        xfree(scratch.data);
1177 
1178        *output_token = token;
1179    }
1180 
1181 cleanup:
1182    if (!verifier_cred_handle && cred_handle) {
1183            krb5_gss_release_cred(&t_minor_status, &cred_handle);
1184    }
1185    krb5_free_context(context);
1186 
1187    /* Solaris Kerberos */
1188    KRB5_LOG(KRB5_ERR,"krb5_gss_accept_sec_context() end, "
1189               "major_status = %d", major_status);
1190    return (major_status);
1191 }