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