"Fossies" - the Fresh Open Source Software Archive

Member "krb5-1.18/src/lib/gssapi/krb5/accept_sec_context.c" (12 Feb 2020, 46399 Bytes) of package /linux/misc/krb5-1.18.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "accept_sec_context.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.17.1_vs_1.18.

    1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
    2 /*
    3  * Copyright 2000, 2004, 2007, 2008  by the Massachusetts Institute of Technology.
    4  * All Rights Reserved.
    5  *
    6  * Export of this software from the United States of America may
    7  *   require a specific license from the United States Government.
    8  *   It is the responsibility of any person or organization contemplating
    9  *   export to obtain such a license before exporting.
   10  *
   11  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
   12  * distribute this software and its documentation for any purpose and
   13  * without fee is hereby granted, provided that the above copyright
   14  * notice appear in all copies and that both that copyright notice and
   15  * this permission notice appear in supporting documentation, and that
   16  * the name of M.I.T. not be used in advertising or publicity pertaining
   17  * to distribution of the software without specific, written prior
   18  * permission.  Furthermore if you modify this software you must label
   19  * your software as modified software and not distribute it in such a
   20  * fashion that it might be confused with the original M.I.T. software.
   21  * M.I.T. makes no representations about the suitability of
   22  * this software for any purpose.  It is provided "as is" without express
   23  * or implied warranty.
   24  */
   25 /*
   26  * Copyright 1993 by OpenVision Technologies, Inc.
   27  *
   28  * Permission to use, copy, modify, distribute, and sell this software
   29  * and its documentation for any purpose is hereby granted without fee,
   30  * provided that the above copyright notice appears in all copies and
   31  * that both that copyright notice and this permission notice appear in
   32  * supporting documentation, and that the name of OpenVision not be used
   33  * in advertising or publicity pertaining to distribution of the software
   34  * without specific, written prior permission. OpenVision makes no
   35  * representations about the suitability of this software for any
   36  * purpose.  It is provided "as is" without express or implied warranty.
   37  *
   38  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
   39  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
   40  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
   41  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
   42  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
   43  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
   44  * PERFORMANCE OF THIS SOFTWARE.
   45  */
   46 
   47 /*
   48  * Copyright (C) 1998 by the FundsXpress, INC.
   49  *
   50  * All rights reserved.
   51  *
   52  * Export of this software from the United States of America may require
   53  * a specific license from the United States Government.  It is the
   54  * responsibility of any person or organization contemplating export to
   55  * obtain such a license before exporting.
   56  *
   57  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
   58  * distribute this software and its documentation for any purpose and
   59  * without fee is hereby granted, provided that the above copyright
   60  * notice appear in all copies and that both that copyright notice and
   61  * this permission notice appear in supporting documentation, and that
   62  * the name of FundsXpress. not be used in advertising or publicity pertaining
   63  * to distribution of the software without specific, written prior
   64  * permission.  FundsXpress makes no representations about the suitability of
   65  * this software for any purpose.  It is provided "as is" without express
   66  * or implied warranty.
   67  *
   68  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
   69  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
   70  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   71  */
   72 /*
   73  * Copyright (c) 2006-2008, Novell, Inc.
   74  * All rights reserved.
   75  *
   76  * Redistribution and use in source and binary forms, with or without
   77  * modification, are permitted provided that the following conditions are met:
   78  *
   79  *   * Redistributions of source code must retain the above copyright notice,
   80  *       this list of conditions and the following disclaimer.
   81  *   * Redistributions in binary form must reproduce the above copyright
   82  *       notice, this list of conditions and the following disclaimer in the
   83  *       documentation and/or other materials provided with the distribution.
   84  *   * The copyright holder's name is not used to endorse or promote products
   85  *       derived from this software without specific prior written permission.
   86  *
   87  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   88  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   89  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   90  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   91  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   92  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   93  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   94  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   95  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   96  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   97  * POSSIBILITY OF SUCH DAMAGE.
   98  */
   99 
  100 #include "k5-int.h"
  101 #include "gssapiP_krb5.h"
  102 #ifdef HAVE_MEMORY_H
  103 #include <memory.h>
  104 #endif
  105 #include <assert.h>
  106 
  107 #ifdef CFX_EXERCISE
  108 #define CFX_ACCEPTOR_SUBKEY (time(0) & 1)
  109 #else
  110 #define CFX_ACCEPTOR_SUBKEY 1
  111 #endif
  112 
  113 #ifndef LEAN_CLIENT
  114 
  115 static OM_uint32
  116 create_constrained_deleg_creds(OM_uint32 *minor_status,
  117                                krb5_gss_cred_id_t verifier_cred_handle,
  118                                krb5_ticket *ticket,
  119                                krb5_gss_cred_id_t *out_cred,
  120                                krb5_context context)
  121 {
  122     OM_uint32 major_status;
  123     krb5_creds krb_creds;
  124     krb5_data *data;
  125     krb5_error_code code;
  126 
  127     assert(out_cred != NULL);
  128     assert(verifier_cred_handle->usage == GSS_C_BOTH);
  129 
  130     memset(&krb_creds, 0, sizeof(krb_creds));
  131     krb_creds.client = ticket->enc_part2->client;
  132     krb_creds.server = ticket->server;
  133     krb_creds.keyblock = *(ticket->enc_part2->session);
  134     krb_creds.ticket_flags = ticket->enc_part2->flags;
  135     krb_creds.times = ticket->enc_part2->times;
  136     krb_creds.magic = KV5M_CREDS;
  137     krb_creds.authdata = NULL;
  138 
  139     code = encode_krb5_ticket(ticket, &data);
  140     if (code) {
  141         *minor_status = code;
  142         return GSS_S_FAILURE;
  143     }
  144 
  145     krb_creds.ticket = *data;
  146 
  147     major_status = kg_compose_deleg_cred(minor_status,
  148                                          verifier_cred_handle,
  149                                          &krb_creds,
  150                                          GSS_C_INDEFINITE,
  151                                          out_cred,
  152                                          NULL,
  153                                          context);
  154 
  155     krb5_free_data(context, data);
  156 
  157     return major_status;
  158 }
  159 
  160 /* Decode, decrypt and store the forwarded creds in the local ccache. */
  161 static krb5_error_code
  162 rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
  163     krb5_context context;
  164     krb5_auth_context auth_context;
  165     krb5_data *inbuf;
  166     krb5_gss_cred_id_t *out_cred;
  167 {
  168     krb5_creds ** creds = NULL;
  169     krb5_error_code retval;
  170     krb5_ccache ccache = NULL;
  171     krb5_gss_cred_id_t cred = NULL;
  172     krb5_auth_context new_auth_ctx = NULL;
  173     krb5_int32 flags_org;
  174 
  175     if ((retval = krb5_auth_con_getflags(context, auth_context, &flags_org)))
  176         return retval;
  177     krb5_auth_con_setflags(context, auth_context,
  178                            0);
  179 
  180     /*
  181      * By the time krb5_rd_cred is called here (after krb5_rd_req has been
  182      * called in krb5_gss_accept_sec_context), the "keyblock" field of
  183      * auth_context contains a pointer to the session key, and the
  184      * "recv_subkey" field might contain a session subkey.  Either of
  185      * these (the "recv_subkey" if it isn't NULL, otherwise the
  186      * "keyblock") might have been used to encrypt the encrypted part of
  187      * the KRB_CRED message that contains the forwarded credentials.  (The
  188      * Java Crypto and Security Implementation from the DSTC in Australia
  189      * always uses the session key.  But apparently it never negotiates a
  190      * subkey, so this code works fine against a JCSI client.)  Up to the
  191      * present, though, GSSAPI clients linked against the MIT code (which
  192      * is almost all GSSAPI clients) don't encrypt the KRB_CRED message at
  193      * all -- at this level.  So if the first call to krb5_rd_cred fails,
  194      * we should call it a second time with another auth context freshly
  195      * created by krb5_auth_con_init.  All of its keyblock fields will be
  196      * NULL, so krb5_rd_cred will assume that the KRB_CRED message is
  197      * unencrypted.  (The MIT code doesn't actually send the KRB_CRED
  198      * message in the clear -- the "authenticator" whose "checksum" ends up
  199      * containing the KRB_CRED message does get encrypted.)
  200      */
  201     if (krb5_rd_cred(context, auth_context, inbuf, &creds, NULL)) {
  202         if ((retval = krb5_auth_con_init(context, &new_auth_ctx)))
  203             goto cleanup;
  204         krb5_auth_con_setflags(context, new_auth_ctx, 0);
  205         if ((retval = krb5_rd_cred(context, new_auth_ctx, inbuf,
  206                                    &creds, NULL)))
  207             goto cleanup;
  208     }
  209 
  210     if ((retval = krb5_cc_new_unique(context, "MEMORY", NULL, &ccache))) {
  211         ccache = NULL;
  212         goto cleanup;
  213     }
  214 
  215     if ((retval = krb5_cc_initialize(context, ccache, creds[0]->client)))
  216         goto cleanup;
  217 
  218     if ((retval = krb5_cc_store_cred(context, ccache, creds[0])))
  219         goto cleanup;
  220 
  221     /* generate a delegated credential handle */
  222     if (out_cred) {
  223         /* allocate memory for a cred_t... */
  224         if (!(cred =
  225               (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec)))) {
  226             retval = ENOMEM; /* out of memory? */
  227             goto cleanup;
  228         }
  229 
  230         /* zero it out... */
  231         memset(cred, 0, sizeof(krb5_gss_cred_id_rec));
  232 
  233         retval = k5_mutex_init(&cred->lock);
  234         if (retval) {
  235             xfree(cred);
  236             cred = NULL;
  237             goto cleanup;
  238         }
  239 
  240         /* copy the client principle into it... */
  241         if ((retval =
  242              kg_init_name(context, creds[0]->client, NULL, NULL, NULL, 0,
  243                           &cred->name))) {
  244             k5_mutex_destroy(&cred->lock);
  245             retval = ENOMEM; /* out of memory? */
  246             xfree(cred); /* clean up memory on failure */
  247             cred = NULL;
  248             goto cleanup;
  249         }
  250 
  251         cred->usage = GSS_C_INITIATE; /* we can't accept with this */
  252         /* cred->name already set */
  253         cred->keytab = NULL; /* no keytab associated with this... */
  254         cred->expire = creds[0]->times.endtime; /* store the end time */
  255         cred->ccache = ccache; /* the ccache containing the credential */
  256         cred->destroy_ccache = 1;
  257         ccache = NULL; /* cred takes ownership so don't destroy */
  258     }
  259 
  260     /* If there were errors, there might have been a memory leak
  261        if (!cred)
  262        if ((retval = krb5_cc_close(context, ccache)))
  263        goto cleanup;
  264     */
  265 cleanup:
  266     if (creds)
  267         krb5_free_tgt_creds(context, creds);
  268 
  269     if (ccache)
  270         (void)krb5_cc_destroy(context, ccache);
  271 
  272     if (out_cred)
  273         *out_cred = cred; /* return credential */
  274 
  275     if (new_auth_ctx)
  276         krb5_auth_con_free(context, new_auth_ctx);
  277 
  278     krb5_auth_con_setflags(context, auth_context, flags_org);
  279 
  280     return retval;
  281 }
  282 
  283 
  284 /*
  285  * Performs third leg of DCE authentication
  286  */
  287 static OM_uint32
  288 kg_accept_dce(minor_status, context_handle, verifier_cred_handle,
  289               input_token, input_chan_bindings, src_name, mech_type,
  290               output_token, ret_flags, time_rec, delegated_cred_handle)
  291     OM_uint32 *minor_status;
  292     gss_ctx_id_t *context_handle;
  293     gss_cred_id_t verifier_cred_handle;
  294     gss_buffer_t input_token;
  295     gss_channel_bindings_t input_chan_bindings;
  296     gss_name_t *src_name;
  297     gss_OID *mech_type;
  298     gss_buffer_t output_token;
  299     OM_uint32 *ret_flags;
  300     OM_uint32 *time_rec;
  301     gss_cred_id_t *delegated_cred_handle;
  302 {
  303     krb5_error_code code;
  304     krb5_gss_ctx_id_rec *ctx = 0;
  305     krb5_timestamp now;
  306     krb5_gss_name_t name = NULL;
  307     krb5_ui_4 nonce = 0;
  308     krb5_data ap_rep;
  309     OM_uint32 major_status = GSS_S_FAILURE;
  310 
  311     output_token->length = 0;
  312     output_token->value = NULL;
  313 
  314     if (mech_type)
  315         *mech_type = GSS_C_NULL_OID;
  316     /* return a bogus cred handle */
  317     if (delegated_cred_handle)
  318         *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
  319 
  320     ctx = (krb5_gss_ctx_id_rec *)*context_handle;
  321 
  322     code = krb5_timeofday(ctx->k5_context, &now);
  323     if (code != 0) {
  324         major_status = GSS_S_FAILURE;
  325         goto fail;
  326     }
  327 
  328     ap_rep.data = input_token->value;
  329     ap_rep.length = input_token->length;
  330 
  331     code = krb5_rd_rep_dce(ctx->k5_context,
  332                            ctx->auth_context,
  333                            &ap_rep,
  334                            &nonce);
  335     if (code != 0) {
  336         major_status = GSS_S_FAILURE;
  337         goto fail;
  338     }
  339 
  340     ctx->established = 1;
  341 
  342     if (src_name) {
  343         code = kg_duplicate_name(ctx->k5_context, ctx->there, &name);
  344         if (code) {
  345             major_status = GSS_S_FAILURE;
  346             goto fail;
  347         }
  348         *src_name = (gss_name_t) name;
  349     }
  350 
  351     if (mech_type)
  352         *mech_type = ctx->mech_used;
  353 
  354     if (time_rec) {
  355         *time_rec = ts_delta(ctx->krb_times.endtime, now) +
  356             ctx->k5_context->clockskew;
  357     }
  358 
  359     /* Never return GSS_C_DELEG_FLAG since we don't support DCE credential
  360      * delegation yet. */
  361     if (ret_flags)
  362         *ret_flags = (ctx->gss_flags & ~GSS_C_DELEG_FLAG);
  363 
  364     *minor_status = 0;
  365 
  366     return GSS_S_COMPLETE;
  367 
  368 fail:
  369     /* real failure code follows */
  370 
  371     (void) krb5_gss_delete_sec_context(minor_status, (gss_ctx_id_t *) &ctx,
  372                                        NULL);
  373     *context_handle = GSS_C_NO_CONTEXT;
  374     *minor_status = code;
  375 
  376     return major_status;
  377 }
  378 
  379 static krb5_error_code
  380 kg_process_extension(krb5_context context,
  381                      krb5_auth_context auth_context,
  382                      int ext_type,
  383                      krb5_data *ext_data,
  384                      krb5_gss_ctx_ext_t exts)
  385 {
  386     krb5_error_code code = 0;
  387 
  388     assert(exts != NULL);
  389 
  390     switch (ext_type) {
  391     case KRB5_GSS_EXTS_IAKERB_FINISHED:
  392         if (exts->iakerb.conv == NULL) {
  393             code = KRB5KRB_AP_ERR_MSG_TYPE; /* XXX */
  394         } else {
  395             krb5_key key;
  396 
  397             code = krb5_auth_con_getrecvsubkey_k(context, auth_context, &key);
  398             if (code != 0)
  399                 break;
  400 
  401             code = iakerb_verify_finished(context, key, exts->iakerb.conv,
  402                                           ext_data);
  403             if (code == 0)
  404                 exts->iakerb.verified = 1;
  405 
  406             krb5_k_free_key(context, key);
  407         }
  408         break;
  409     default:
  410         break;
  411     }
  412 
  413     return code;
  414 }
  415 
  416 static OM_uint32
  417 kg_accept_krb5(minor_status, context_handle,
  418                verifier_cred_handle, input_token,
  419                input_chan_bindings, src_name, mech_type,
  420                output_token, ret_flags, time_rec,
  421                delegated_cred_handle, exts)
  422     OM_uint32 *minor_status;
  423     gss_ctx_id_t *context_handle;
  424     gss_cred_id_t verifier_cred_handle;
  425     gss_buffer_t input_token;
  426     gss_channel_bindings_t input_chan_bindings;
  427     gss_name_t *src_name;
  428     gss_OID *mech_type;
  429     gss_buffer_t output_token;
  430     OM_uint32 *ret_flags;
  431     OM_uint32 *time_rec;
  432     gss_cred_id_t *delegated_cred_handle;
  433     krb5_gss_ctx_ext_t exts;
  434 {
  435     krb5_context context;
  436     unsigned char *ptr, *ptr2;
  437     char *sptr;
  438     OM_uint32 tmp;
  439     size_t md5len;
  440     krb5_gss_cred_id_t cred = 0;
  441     krb5_data ap_rep, ap_req;
  442     unsigned int i;
  443     krb5_error_code code;
  444     krb5_address addr, *paddr;
  445     krb5_authenticator *authdat = 0;
  446     krb5_checksum reqcksum;
  447     krb5_gss_name_t name = NULL;
  448     krb5_ui_4 gss_flags = 0;
  449     krb5_gss_ctx_id_rec *ctx = NULL;
  450     krb5_timestamp now;
  451     gss_buffer_desc token;
  452     krb5_auth_context auth_context = NULL;
  453     krb5_ticket * ticket = NULL;
  454     int option_id;
  455     krb5_data option;
  456     const gss_OID_desc *mech_used = NULL;
  457     OM_uint32 major_status = GSS_S_FAILURE;
  458     OM_uint32 tmp_minor_status;
  459     krb5_error krb_error_data;
  460     krb5_data scratch;
  461     gss_cred_id_t defcred = GSS_C_NO_CREDENTIAL;
  462     krb5_gss_cred_id_t deleg_cred = NULL;
  463     krb5int_access kaccess;
  464     int cred_rcache = 0;
  465     int no_encap = 0;
  466     int token_deleg_flag = 0;
  467     krb5_flags ap_req_options = 0;
  468     krb5_enctype negotiated_etype;
  469     krb5_authdata_context ad_context = NULL;
  470     krb5_principal accprinc = NULL;
  471     krb5_ap_req *request = NULL;
  472 
  473     code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
  474     if (code) {
  475         *minor_status = code;
  476         return(GSS_S_FAILURE);
  477     }
  478 
  479     code = krb5_gss_init_context(&context);
  480     if (code) {
  481         *minor_status = code;
  482         return GSS_S_FAILURE;
  483     }
  484 
  485     /* set up returns to be freeable */
  486 
  487     if (src_name)
  488         *src_name = (gss_name_t) NULL;
  489     output_token->length = 0;
  490     output_token->value = NULL;
  491     token.value = 0;
  492     reqcksum.contents = 0;
  493     ap_req.data = 0;
  494     ap_rep.data = 0;
  495 
  496     if (mech_type)
  497         *mech_type = GSS_C_NULL_OID;
  498     /* return a bogus cred handle */
  499     if (delegated_cred_handle)
  500         *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
  501 
  502     /* handle default cred handle */
  503     if (verifier_cred_handle == GSS_C_NO_CREDENTIAL) {
  504         major_status = krb5_gss_acquire_cred(minor_status, GSS_C_NO_NAME,
  505                                              GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
  506                                              GSS_C_ACCEPT, &defcred,
  507                                              NULL, NULL);
  508         if (major_status != GSS_S_COMPLETE) {
  509             code = *minor_status;
  510             goto fail;
  511         }
  512         verifier_cred_handle = defcred;
  513     }
  514 
  515     /* Resolve any initiator state in the verifier cred and lock it. */
  516     major_status = kg_cred_resolve(minor_status, context, verifier_cred_handle,
  517                                    GSS_C_NO_NAME);
  518     if (GSS_ERROR(major_status)) {
  519         code = *minor_status;
  520         goto fail;
  521     }
  522     cred = (krb5_gss_cred_id_t)verifier_cred_handle;
  523 
  524     /* make sure the supplied credentials are valid for accept */
  525 
  526     if ((cred->usage != GSS_C_ACCEPT) &&
  527         (cred->usage != GSS_C_BOTH)) {
  528         code = 0;
  529         major_status = GSS_S_NO_CRED;
  530         goto fail;
  531     }
  532 
  533     /* verify the token's integrity, and leave the token in ap_req.
  534        figure out which mech oid was used, and save it */
  535 
  536     ptr = (unsigned char *) input_token->value;
  537 
  538     if (!(code = g_verify_token_header(gss_mech_krb5,
  539                                        &(ap_req.length),
  540                                        &ptr, KG_TOK_CTX_AP_REQ,
  541                                        input_token->length, 1))) {
  542         mech_used = gss_mech_krb5;
  543     } else if ((code == G_WRONG_MECH)
  544                &&!(code = g_verify_token_header((gss_OID) gss_mech_iakerb,
  545                                                 &(ap_req.length),
  546                                                 &ptr, KG_TOK_CTX_AP_REQ,
  547                                                 input_token->length, 1))) {
  548         mech_used = gss_mech_iakerb;
  549     } else if ((code == G_WRONG_MECH)
  550                &&!(code = g_verify_token_header((gss_OID) gss_mech_krb5_wrong,
  551                                                 &(ap_req.length),
  552                                                 &ptr, KG_TOK_CTX_AP_REQ,
  553                                                 input_token->length, 1))) {
  554         mech_used = gss_mech_krb5_wrong;
  555     } else if ((code == G_WRONG_MECH) &&
  556                !(code = g_verify_token_header(gss_mech_krb5_old,
  557                                               &(ap_req.length),
  558                                               &ptr, KG_TOK_CTX_AP_REQ,
  559                                               input_token->length, 1))) {
  560         /*
  561          * Previous versions of this library used the old mech_id
  562          * and some broken behavior (wrong IV on checksum
  563          * encryption).  We support the old mech_id for
  564          * compatibility, and use it to decide when to use the
  565          * old behavior.
  566          */
  567         mech_used = gss_mech_krb5_old;
  568     } else if (code == G_WRONG_TOKID) {
  569         major_status = GSS_S_CONTINUE_NEEDED;
  570         code = KRB5KRB_AP_ERR_MSG_TYPE;
  571         mech_used = gss_mech_krb5;
  572         goto fail;
  573     } else if (code == G_BAD_TOK_HEADER) {
  574         /* DCE style not encapsulated */
  575         ap_req.length = input_token->length;
  576         ap_req.data = input_token->value;
  577         mech_used = gss_mech_krb5;
  578         no_encap = 1;
  579     } else {
  580         major_status = GSS_S_DEFECTIVE_TOKEN;
  581         goto fail;
  582     }
  583 
  584     sptr = (char *) ptr;
  585     TREAD_STR(sptr, ap_req.data, ap_req.length);
  586 
  587     /* construct the sender_addr */
  588 
  589     if ((input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) &&
  590         (input_chan_bindings->initiator_addrtype == GSS_C_AF_INET)) {
  591         /* XXX is this right? */
  592         addr.addrtype = ADDRTYPE_INET;
  593         addr.length = input_chan_bindings->initiator_address.length;
  594         addr.contents = input_chan_bindings->initiator_address.value;
  595 
  596         paddr = &addr;
  597     } else {
  598         paddr = NULL;
  599     }
  600 
  601     /* decode the AP_REQ message */
  602     code = decode_krb5_ap_req(&ap_req, &request);
  603     if (code) {
  604         major_status = GSS_S_FAILURE;
  605         goto done;
  606     }
  607     ticket = request->ticket;
  608 
  609     /* decode the message */
  610 
  611     if ((code = krb5_auth_con_init(context, &auth_context))) {
  612         major_status = GSS_S_FAILURE;
  613         save_error_info((OM_uint32)code, context);
  614         goto fail;
  615     }
  616     if (cred->rcache) {
  617         cred_rcache = 1;
  618         if ((code = krb5_auth_con_setrcache(context, auth_context, cred->rcache))) {
  619             major_status = GSS_S_FAILURE;
  620             goto fail;
  621         }
  622     }
  623     if ((code = krb5_auth_con_setaddrs(context, auth_context, NULL, paddr))) {
  624         major_status = GSS_S_FAILURE;
  625         goto fail;
  626     }
  627 
  628     /* Limit the encryption types negotiated (if requested). */
  629     if (cred->req_enctypes) {
  630         if ((code = krb5_auth_con_setpermetypes(context, auth_context,
  631                                                 cred->req_enctypes))) {
  632             major_status = GSS_S_FAILURE;
  633             goto fail;
  634         }
  635     }
  636 
  637     if (!cred->default_identity) {
  638         if ((code = kg_acceptor_princ(context, cred->name, &accprinc))) {
  639             major_status = GSS_S_FAILURE;
  640             goto fail;
  641         }
  642     }
  643 
  644     code = krb5_rd_req_decoded(context, &auth_context, request, accprinc,
  645                                cred->keytab, &ap_req_options, NULL);
  646 
  647     krb5_free_principal(context, accprinc);
  648     if (code) {
  649         major_status = GSS_S_FAILURE;
  650         goto fail;
  651     }
  652     krb5_auth_con_setflags(context, auth_context,
  653                            KRB5_AUTH_CONTEXT_DO_SEQUENCE);
  654 
  655     krb5_auth_con_getauthenticator(context, auth_context, &authdat);
  656 
  657     if (authdat->checksum == NULL) {
  658         /*
  659          * Some SMB client implementations use handcrafted GSSAPI code that
  660          * does not provide a checksum.  MS-KILE documents that the Microsoft
  661          * implementation considers a missing checksum acceptable; the server
  662          * assumes all flags are unset in this case, and does not check channel
  663          * bindings.
  664          */
  665         gss_flags = 0;
  666     } else if (authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) {
  667         /* Samba does not send 0x8003 GSS-API checksums */
  668         krb5_boolean valid;
  669         krb5_key subkey;
  670         krb5_data zero;
  671 
  672         code = krb5_auth_con_getkey_k(context, auth_context, &subkey);
  673         if (code) {
  674             major_status = GSS_S_FAILURE;
  675             goto fail;
  676         }
  677 
  678         zero.length = 0;
  679         zero.data = "";
  680 
  681         code = krb5_k_verify_checksum(context,
  682                                       subkey,
  683                                       KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM,
  684                                       &zero,
  685                                       authdat->checksum,
  686                                       &valid);
  687         krb5_k_free_key(context, subkey);
  688         if (code || !valid) {
  689             major_status = GSS_S_BAD_SIG;
  690             goto fail;
  691         }
  692 
  693         /* Use ap_options from the request to guess the mutual flag. */
  694         gss_flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
  695         if (ap_req_options & AP_OPTS_MUTUAL_REQUIRED)
  696             gss_flags |= GSS_C_MUTUAL_FLAG;
  697     } else {
  698         /* gss krb5 v1 */
  699 
  700         /* stash this now, for later. */
  701         code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &md5len);
  702         if (code) {
  703             major_status = GSS_S_FAILURE;
  704             goto fail;
  705         }
  706 
  707         /* verify that the checksum is correct */
  708 
  709         /*
  710           The checksum may be either exactly 24 bytes, in which case
  711           no options are specified, or greater than 24 bytes, in which case
  712           one or more options are specified. Currently, the only valid
  713           option is KRB5_GSS_FOR_CREDS_OPTION ( = 1 ).
  714         */
  715 
  716         if ((authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) ||
  717             (authdat->checksum->length < 24)) {
  718             code = 0;
  719             major_status = GSS_S_BAD_BINDINGS;
  720             goto fail;
  721         }
  722 
  723         ptr = (unsigned char *) authdat->checksum->contents;
  724 
  725         TREAD_INT(ptr, tmp, 0);
  726 
  727         if (tmp != md5len) {
  728             code = KG_BAD_LENGTH;
  729             major_status = GSS_S_FAILURE;
  730             goto fail;
  731         }
  732 
  733         /*
  734           The following section of code attempts to implement the
  735           optional channel binding facility as described in RFC2743.
  736 
  737           Since this facility is optional channel binding may or may
  738           not have been provided by either the client or the server.
  739 
  740           If the server has specified input_chan_bindings equal to
  741           GSS_C_NO_CHANNEL_BINDINGS then we skip the check.  If
  742           the server does provide channel bindings then we compute
  743           a checksum and compare against those provided by the
  744           client.         */
  745 
  746         if ((code = kg_checksum_channel_bindings(context,
  747                                                  input_chan_bindings,
  748                                                  &reqcksum))) {
  749             major_status = GSS_S_BAD_BINDINGS;
  750             goto fail;
  751         }
  752 
  753         /* Always read the clients bindings - eventhough we might ignore them */
  754         TREAD_STR(ptr, ptr2, reqcksum.length);
  755 
  756         if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS ) {
  757             if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
  758                 xfree(reqcksum.contents);
  759                 reqcksum.contents = 0;
  760                 code = 0;
  761                 major_status = GSS_S_BAD_BINDINGS;
  762                 goto fail;
  763             }
  764 
  765         }
  766 
  767         xfree(reqcksum.contents);
  768         reqcksum.contents = 0;
  769 
  770         /* Read the token flags.  Remember if GSS_C_DELEG_FLAG was set, but
  771          * mask it out until we actually read a delegated credential. */
  772         TREAD_INT(ptr, gss_flags, 0);
  773         token_deleg_flag = (gss_flags & GSS_C_DELEG_FLAG);
  774         gss_flags &= ~GSS_C_DELEG_FLAG;
  775 
  776         /* if the checksum length > 24, there are options to process */
  777 
  778         i = authdat->checksum->length - 24;
  779         if (i && token_deleg_flag) {
  780             if (i >= 4) {
  781                 TREAD_INT16(ptr, option_id, 0);
  782                 TREAD_INT16(ptr, option.length, 0);
  783                 i -= 4;
  784 
  785                 if (i < option.length) {
  786                     code = KG_BAD_LENGTH;
  787                     major_status = GSS_S_FAILURE;
  788                     goto fail;
  789                 }
  790 
  791                 /* have to use ptr2, since option.data is wrong type and
  792                    macro uses ptr as both lvalue and rvalue */
  793 
  794                 TREAD_STR(ptr, ptr2, option.length);
  795                 option.data = (char *) ptr2;
  796 
  797                 i -= option.length;
  798 
  799                 if (option_id != KRB5_GSS_FOR_CREDS_OPTION) {
  800                     major_status = GSS_S_FAILURE;
  801                     goto fail;
  802                 }
  803 
  804                 /* store the delegated credential */
  805 
  806                 code = rd_and_store_for_creds(context, auth_context, &option,
  807                                               (delegated_cred_handle) ?
  808                                               &deleg_cred : NULL);
  809                 if (code) {
  810                     major_status = GSS_S_FAILURE;
  811                     goto fail;
  812                 }
  813 
  814                 gss_flags |= GSS_C_DELEG_FLAG;
  815             } /* if i >= 4 */
  816             /* ignore any additional trailing data, for now */
  817         }
  818         while (i > 0) {
  819             /* Process Type-Length-Data options */
  820             if (i < 8) {
  821                 code = KG_BAD_LENGTH;
  822                 major_status = GSS_S_FAILURE;
  823                 goto fail;
  824             }
  825             TREAD_INT(ptr, option_id, 1);
  826             TREAD_INT(ptr, option.length, 1);
  827             i -= 8;
  828             if (i < option.length) {
  829                 code = KG_BAD_LENGTH;
  830                 major_status = GSS_S_FAILURE;
  831                 goto fail;
  832             }
  833             TREAD_STR(ptr, ptr2, option.length);
  834             option.data = (char *)ptr2;
  835 
  836             i -= option.length;
  837 
  838             code = kg_process_extension(context, auth_context,
  839                                         option_id, &option, exts);
  840             if (code != 0) {
  841                 major_status = GSS_S_FAILURE;
  842                 goto fail;
  843             }
  844         }
  845     }
  846 
  847     if (exts->iakerb.conv && !exts->iakerb.verified) {
  848         major_status = GSS_S_BAD_SIG;
  849         goto fail;
  850     }
  851 
  852     /* only DCE_STYLE clients are allowed to send raw AP-REQs */
  853     if (no_encap != ((gss_flags & GSS_C_DCE_STYLE) != 0)) {
  854         major_status = GSS_S_DEFECTIVE_TOKEN;
  855         goto fail;
  856     }
  857 
  858     /* create the ctx struct and start filling it in */
  859 
  860     if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
  861         == NULL) {
  862         code = ENOMEM;
  863         major_status = GSS_S_FAILURE;
  864         goto fail;
  865     }
  866 
  867     memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
  868     ctx->magic = KG_CONTEXT;
  869     ctx->mech_used = (gss_OID) mech_used;
  870     ctx->auth_context = auth_context;
  871     ctx->initiate = 0;
  872     ctx->gss_flags = (GSS_C_TRANS_FLAG |
  873                       ((gss_flags) & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |
  874                                       GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
  875                                       GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG |
  876                                       GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG |
  877                                       GSS_C_EXTENDED_ERROR_FLAG)));
  878     ctx->seed_init = 0;
  879     ctx->cred_rcache = cred_rcache;
  880 
  881     /* XXX move this into gss_name_t */
  882     if (        (code = krb5_merge_authdata(context,
  883                                             ticket->enc_part2->authorization_data,
  884                                             authdat->authorization_data,
  885                                             &ctx->authdata))) {
  886         major_status = GSS_S_FAILURE;
  887         goto fail;
  888     }
  889     if ((code = kg_init_name(context, ticket->server, NULL, NULL, NULL, 0,
  890                              &ctx->here))) {
  891         major_status = GSS_S_FAILURE;
  892         goto fail;
  893     }
  894     if ((code = krb5_auth_con_get_authdata_context(context, auth_context,
  895                                                    &ad_context))) {
  896         major_status = GSS_S_FAILURE;
  897         goto fail;
  898     }
  899     if ((code = kg_init_name(context, authdat->client, NULL, NULL,
  900                              ad_context, KG_INIT_NAME_NO_COPY, &ctx->there))) {
  901         major_status = GSS_S_FAILURE;
  902         goto fail;
  903     }
  904     /* Now owned by ctx->there */
  905     authdat->client = NULL;
  906     krb5_auth_con_set_authdata_context(context, auth_context, NULL);
  907 
  908     if ((code = krb5_auth_con_getrecvsubkey_k(context, auth_context,
  909                                               &ctx->subkey))) {
  910         major_status = GSS_S_FAILURE;
  911         goto fail;
  912     }
  913 
  914     /* use the session key if the subkey isn't present */
  915 
  916     if (ctx->subkey == NULL) {
  917         if ((code = krb5_auth_con_getkey_k(context, auth_context,
  918                                            &ctx->subkey))) {
  919             major_status = GSS_S_FAILURE;
  920             goto fail;
  921         }
  922     }
  923 
  924     if (ctx->subkey == NULL) {
  925         /* this isn't a very good error, but it's not clear to me this
  926            can actually happen */
  927         major_status = GSS_S_FAILURE;
  928         code = KRB5KDC_ERR_NULL_KEY;
  929         goto fail;
  930     }
  931 
  932     ctx->enc = NULL;
  933     ctx->seq = NULL;
  934     ctx->have_acceptor_subkey = 0;
  935     /* DCE_STYLE implies acceptor_subkey */
  936     if ((ctx->gss_flags & GSS_C_DCE_STYLE) == 0) {
  937         code = kg_setup_keys(context, ctx, ctx->subkey, &ctx->cksumtype);
  938         if (code) {
  939             major_status = GSS_S_FAILURE;
  940             goto fail;
  941         }
  942     }
  943     ctx->krb_times = ticket->enc_part2->times; /* struct copy */
  944     ctx->krb_flags = ticket->enc_part2->flags;
  945 
  946     if (delegated_cred_handle != NULL &&
  947         deleg_cred == NULL && /* no unconstrained delegation */
  948         cred->usage == GSS_C_BOTH) {
  949         /*
  950          * Now, we always fabricate a delegated credentials handle
  951          * containing the service ticket to ourselves, which can be
  952          * used for S4U2Proxy.
  953          */
  954         major_status = create_constrained_deleg_creds(minor_status, cred,
  955                                                       ticket, &deleg_cred,
  956                                                       context);
  957         if (GSS_ERROR(major_status))
  958             goto fail;
  959         ctx->gss_flags |= GSS_C_DELEG_FLAG;
  960     }
  961 
  962     {
  963         krb5_int32 seq_temp;
  964         krb5_auth_con_getremoteseqnumber(context, auth_context, &seq_temp);
  965         ctx->seq_recv = seq_temp;
  966     }
  967 
  968     if ((code = krb5_timeofday(context, &now))) {
  969         major_status = GSS_S_FAILURE;
  970         goto fail;
  971     }
  972 
  973     code = g_seqstate_init(&ctx->seqstate, ctx->seq_recv,
  974                            (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
  975                            (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0,
  976                            ctx->proto);
  977     if (code) {
  978         major_status = GSS_S_FAILURE;
  979         goto fail;
  980     }
  981 
  982     /* DCE_STYLE implies mutual authentication */
  983     if (ctx->gss_flags & GSS_C_DCE_STYLE)
  984         ctx->gss_flags |= GSS_C_MUTUAL_FLAG;
  985 
  986     /* at this point, the entire context structure is filled in,
  987        so it can be released.  */
  988 
  989     /* generate an AP_REP if necessary */
  990 
  991     if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
  992         unsigned char * ptr3;
  993         krb5_int32 seq_temp;
  994         int cfx_generate_subkey;
  995 
  996         /*
  997          * Do not generate a subkey per RFC 4537 unless we are upgrading to CFX,
  998          * because pre-CFX tokens do not indicate which key to use. (Note that
  999          * DCE_STYLE implies that we will use a subkey.)
 1000          */
 1001         if (ctx->proto == 0 &&
 1002             (ctx->gss_flags & GSS_C_DCE_STYLE) == 0 &&
 1003             (ap_req_options & AP_OPTS_USE_SUBKEY)) {
 1004             code = (*kaccess.auth_con_get_subkey_enctype)(context,
 1005                                                           auth_context,
 1006                                                           &negotiated_etype);
 1007             if (code != 0) {
 1008                 major_status = GSS_S_FAILURE;
 1009                 goto fail;
 1010             }
 1011 
 1012             switch (negotiated_etype) {
 1013             case ENCTYPE_DES3_CBC_SHA1:
 1014             case ENCTYPE_ARCFOUR_HMAC:
 1015             case ENCTYPE_ARCFOUR_HMAC_EXP:
 1016                 /* RFC 4121 accidentally omits RC4-HMAC-EXP as a "not-newer"
 1017                  * enctype, even though RFC 4757 treats it as one. */
 1018                 ap_req_options &= ~(AP_OPTS_USE_SUBKEY);
 1019                 break;
 1020             }
 1021         }
 1022 
 1023         if (ctx->proto == 1 || (ctx->gss_flags & GSS_C_DCE_STYLE) ||
 1024             (ap_req_options & AP_OPTS_USE_SUBKEY))
 1025             cfx_generate_subkey = CFX_ACCEPTOR_SUBKEY;
 1026         else
 1027             cfx_generate_subkey = 0;
 1028 
 1029         if (cfx_generate_subkey) {
 1030             krb5_int32 acflags;
 1031             code = krb5_auth_con_getflags(context, auth_context, &acflags);
 1032             if (code == 0) {
 1033                 acflags |= KRB5_AUTH_CONTEXT_USE_SUBKEY;
 1034                 code = krb5_auth_con_setflags(context, auth_context, acflags);
 1035             }
 1036             if (code) {
 1037                 major_status = GSS_S_FAILURE;
 1038                 goto fail;
 1039             }
 1040         }
 1041 
 1042         if ((code = krb5_mk_rep(context, auth_context, &ap_rep))) {
 1043             major_status = GSS_S_FAILURE;
 1044             goto fail;
 1045         }
 1046 
 1047         krb5_auth_con_getlocalseqnumber(context, auth_context, &seq_temp);
 1048         ctx->seq_send = seq_temp & 0xffffffffL;
 1049 
 1050         if (cfx_generate_subkey) {
 1051             /* Get the new acceptor subkey.  With the code above, there
 1052                should always be one if we make it to this point.  */
 1053             code = krb5_auth_con_getsendsubkey_k(context, auth_context,
 1054                                                  &ctx->acceptor_subkey);
 1055             if (code != 0) {
 1056                 major_status = GSS_S_FAILURE;
 1057                 goto fail;
 1058             }
 1059             ctx->have_acceptor_subkey = 1;
 1060 
 1061             code = kg_setup_keys(context, ctx, ctx->acceptor_subkey,
 1062                                  &ctx->acceptor_subkey_cksumtype);
 1063             if (code) {
 1064                 major_status = GSS_S_FAILURE;
 1065                 goto fail;
 1066             }
 1067         }
 1068 
 1069         /* the reply token hasn't been sent yet, but that's ok. */
 1070         if (ctx->gss_flags & GSS_C_DCE_STYLE) {
 1071             assert(ctx->have_acceptor_subkey);
 1072 
 1073             /* in order to force acceptor subkey to be used, don't set PROT_READY */
 1074 
 1075             /* Raw AP-REP is returned */
 1076             code = data_to_gss(&ap_rep, output_token);
 1077             if (code)
 1078             {
 1079                 major_status = GSS_S_FAILURE;
 1080                 goto fail;
 1081             }
 1082 
 1083             ctx->established = 0;
 1084 
 1085             *context_handle = (gss_ctx_id_t)ctx;
 1086             *minor_status = 0;
 1087             major_status = GSS_S_CONTINUE_NEEDED;
 1088 
 1089             /* Only last leg should set return arguments */
 1090             goto fail;
 1091         } else
 1092             ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
 1093 
 1094         ctx->established = 1;
 1095 
 1096         token.length = g_token_size(mech_used, ap_rep.length);
 1097 
 1098         if ((token.value = (unsigned char *) gssalloc_malloc(token.length))
 1099             == NULL) {
 1100             major_status = GSS_S_FAILURE;
 1101             code = ENOMEM;
 1102             goto fail;
 1103         }
 1104         ptr3 = token.value;
 1105         g_make_token_header(mech_used, ap_rep.length,
 1106                             &ptr3, KG_TOK_CTX_AP_REP);
 1107 
 1108         TWRITE_STR(ptr3, ap_rep.data, ap_rep.length);
 1109 
 1110         ctx->established = 1;
 1111 
 1112     } else {
 1113         token.length = 0;
 1114         token.value = NULL;
 1115         ctx->seq_send = ctx->seq_recv;
 1116 
 1117         ctx->established = 1;
 1118     }
 1119 
 1120     /* set the return arguments */
 1121 
 1122     if (src_name) {
 1123         code = kg_duplicate_name(context, ctx->there, &name);
 1124         if (code) {
 1125             major_status = GSS_S_FAILURE;
 1126             goto fail;
 1127         }
 1128     }
 1129 
 1130     if (mech_type)
 1131         *mech_type = (gss_OID) mech_used;
 1132 
 1133     /* Add the maximum allowable clock skew as a grace period for context
 1134      * expiration, just as we do for the ticket. */
 1135     if (time_rec)
 1136         *time_rec = ts_delta(ctx->krb_times.endtime, now) + context->clockskew;
 1137 
 1138     if (ret_flags)
 1139         *ret_flags = ctx->gss_flags;
 1140 
 1141     *context_handle = (gss_ctx_id_t)ctx;
 1142     *output_token = token;
 1143 
 1144     if (src_name)
 1145         *src_name = (gss_name_t) name;
 1146 
 1147     if (delegated_cred_handle)
 1148         *delegated_cred_handle = (gss_cred_id_t) deleg_cred;
 1149 
 1150     /* finally! */
 1151 
 1152     *minor_status = 0;
 1153     major_status = GSS_S_COMPLETE;
 1154 
 1155 fail:
 1156     if (authdat)
 1157         krb5_free_authenticator(context, authdat);
 1158     /* The ctx structure has the handle of the auth_context */
 1159     if (auth_context && !ctx) {
 1160         if (cred_rcache)
 1161             (void)krb5_auth_con_setrcache(context, auth_context, NULL);
 1162 
 1163         krb5_auth_con_free(context, auth_context);
 1164     }
 1165     if (reqcksum.contents)
 1166         xfree(reqcksum.contents);
 1167     if (ap_rep.data)
 1168         krb5_free_data_contents(context, &ap_rep);
 1169     if (major_status == GSS_S_COMPLETE ||
 1170         (major_status == GSS_S_CONTINUE_NEEDED && code != KRB5KRB_AP_ERR_MSG_TYPE)) {
 1171         ctx->k5_context = context;
 1172         context = NULL;
 1173         goto done;
 1174     }
 1175 
 1176     /* from here on is the real "fail" code */
 1177 
 1178     if (ctx)
 1179         (void) krb5_gss_delete_sec_context(&tmp_minor_status,
 1180                                            (gss_ctx_id_t *) &ctx, NULL);
 1181     if (deleg_cred) { /* free memory associated with the deleg credential */
 1182         if (deleg_cred->ccache)
 1183             (void)krb5_cc_close(context, deleg_cred->ccache);
 1184         if (deleg_cred->name)
 1185             kg_release_name(context, &deleg_cred->name);
 1186         xfree(deleg_cred);
 1187     }
 1188     if (token.value)
 1189         xfree(token.value);
 1190     if (name) {
 1191         (void) kg_release_name(context, &name);
 1192     }
 1193 
 1194     *minor_status = code;
 1195 
 1196     /* We may have failed before being able to read the GSS flags from the
 1197      * authenticator, so also check the request AP options. */
 1198     if (cred != NULL && request != NULL &&
 1199         ((gss_flags & GSS_C_MUTUAL_FLAG) ||
 1200          (request->ap_options & AP_OPTS_MUTUAL_REQUIRED) ||
 1201          major_status == GSS_S_CONTINUE_NEEDED)) {
 1202         unsigned int tmsglen;
 1203         int toktype;
 1204 
 1205         /*
 1206          * The client is expecting a response, so we can send an
 1207          * error token back
 1208          */
 1209         memset(&krb_error_data, 0, sizeof(krb_error_data));
 1210 
 1211         code -= ERROR_TABLE_BASE_krb5;
 1212         if (code < 0 || code > KRB_ERR_MAX)
 1213             code = 60 /* KRB_ERR_GENERIC */;
 1214 
 1215         krb_error_data.error = code;
 1216         (void) krb5_us_timeofday(context, &krb_error_data.stime,
 1217                                  &krb_error_data.susec);
 1218 
 1219         krb_error_data.server = ticket->server;
 1220         code = krb5_mk_error(context, &krb_error_data, &scratch);
 1221         if (code)
 1222             goto done;
 1223 
 1224         tmsglen = scratch.length;
 1225         toktype = KG_TOK_CTX_ERROR;
 1226 
 1227         token.length = g_token_size(mech_used, tmsglen);
 1228         token.value = gssalloc_malloc(token.length);
 1229         if (!token.value)
 1230             goto done;
 1231 
 1232         ptr = token.value;
 1233         g_make_token_header(mech_used, tmsglen, &ptr, toktype);
 1234 
 1235         TWRITE_STR(ptr, scratch.data, scratch.length);
 1236         krb5_free_data_contents(context, &scratch);
 1237 
 1238         *output_token = token;
 1239     }
 1240 
 1241 done:
 1242     krb5_free_ap_req(context, request);
 1243     if (cred)
 1244         k5_mutex_unlock(&cred->lock);
 1245     if (defcred)
 1246         krb5_gss_release_cred(&tmp_minor_status, &defcred);
 1247     if (context) {
 1248         if (major_status && *minor_status)
 1249             save_error_info(*minor_status, context);
 1250         krb5_free_context(context);
 1251     }
 1252     return (major_status);
 1253 }
 1254 #endif /* LEAN_CLIENT */
 1255 
 1256 OM_uint32 KRB5_CALLCONV
 1257 krb5_gss_accept_sec_context_ext(
 1258     OM_uint32 *minor_status,
 1259     gss_ctx_id_t *context_handle,
 1260     gss_cred_id_t verifier_cred_handle,
 1261     gss_buffer_t input_token,
 1262     gss_channel_bindings_t input_chan_bindings,
 1263     gss_name_t *src_name,
 1264     gss_OID *mech_type,
 1265     gss_buffer_t output_token,
 1266     OM_uint32 *ret_flags,
 1267     OM_uint32 *time_rec,
 1268     gss_cred_id_t *delegated_cred_handle,
 1269     krb5_gss_ctx_ext_t exts)
 1270 {
 1271     krb5_gss_ctx_id_rec *ctx = (krb5_gss_ctx_id_rec *)*context_handle;
 1272 
 1273     /*
 1274      * Context handle must be unspecified.  Actually, it must be
 1275      * non-established, but currently, accept_sec_context never returns
 1276      * a non-established context handle.
 1277      */
 1278     /*SUPPRESS 29*/
 1279     if (ctx != NULL) {
 1280         if (ctx->established == 0 && (ctx->gss_flags & GSS_C_DCE_STYLE)) {
 1281             return kg_accept_dce(minor_status, context_handle,
 1282                                  verifier_cred_handle, input_token,
 1283                                  input_chan_bindings, src_name, mech_type,
 1284                                  output_token, ret_flags, time_rec,
 1285                                  delegated_cred_handle);
 1286         } else {
 1287             *minor_status = EINVAL;
 1288             save_error_string(EINVAL, "accept_sec_context called with existing context handle");
 1289             return GSS_S_FAILURE;
 1290         }
 1291     }
 1292 
 1293     return kg_accept_krb5(minor_status, context_handle,
 1294                           verifier_cred_handle, input_token,
 1295                           input_chan_bindings, src_name, mech_type,
 1296                           output_token, ret_flags, time_rec,
 1297                           delegated_cred_handle, exts);
 1298 }
 1299 
 1300 OM_uint32 KRB5_CALLCONV
 1301 krb5_gss_accept_sec_context(minor_status, context_handle,
 1302                             verifier_cred_handle, input_token,
 1303                             input_chan_bindings, src_name, mech_type,
 1304                             output_token, ret_flags, time_rec,
 1305                             delegated_cred_handle)
 1306     OM_uint32 *minor_status;
 1307     gss_ctx_id_t *context_handle;
 1308     gss_cred_id_t verifier_cred_handle;
 1309     gss_buffer_t input_token;
 1310     gss_channel_bindings_t input_chan_bindings;
 1311     gss_name_t *src_name;
 1312     gss_OID *mech_type;
 1313     gss_buffer_t output_token;
 1314     OM_uint32 *ret_flags;
 1315     OM_uint32 *time_rec;
 1316     gss_cred_id_t *delegated_cred_handle;
 1317 {
 1318     krb5_gss_ctx_ext_rec exts;
 1319 
 1320     memset(&exts, 0, sizeof(exts));
 1321 
 1322     return krb5_gss_accept_sec_context_ext(minor_status,
 1323                                            context_handle,
 1324                                            verifier_cred_handle,
 1325                                            input_token,
 1326                                            input_chan_bindings,
 1327                                            src_name,
 1328                                            mech_type,
 1329                                            output_token,
 1330                                            ret_flags,
 1331                                            time_rec,
 1332                                            delegated_cred_handle,
 1333                                            &exts);
 1334 }