LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/gssapi/spnego - compat.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 0 303 0.0 %
Date: 2024-02-28 12:06:22 Functions: 0 17 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2004, PADL Software Pty Ltd.
       3             :  * All rights reserved.
       4             :  *
       5             :  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
       6             :  *
       7             :  * Redistribution and use in source and binary forms, with or without
       8             :  * modification, are permitted provided that the following conditions
       9             :  * are met:
      10             :  *
      11             :  * 1. Redistributions of source code must retain the above copyright
      12             :  *    notice, this list of conditions and the following disclaimer.
      13             :  *
      14             :  * 2. Redistributions in binary form must reproduce the above copyright
      15             :  *    notice, this list of conditions and the following disclaimer in the
      16             :  *    documentation and/or other materials provided with the distribution.
      17             :  *
      18             :  * 3. Neither the name of PADL Software nor the names of its contributors
      19             :  *    may be used to endorse or promote products derived from this software
      20             :  *    without specific prior written permission.
      21             :  *
      22             :  * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
      23             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      24             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      25             :  * ARE DISCLAIMED.  IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
      26             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      27             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      28             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      29             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      30             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      31             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      32             :  * SUCH DAMAGE.
      33             :  */
      34             : 
      35             : #include "spnego_locl.h"
      36             : 
      37             : /*
      38             :  * Apparently Microsoft got the OID wrong, and used
      39             :  * 1.2.840.48018.1.2.2 instead. We need both this and
      40             :  * the correct Kerberos OID here in order to deal with
      41             :  * this. Because this is manifest in SPNEGO only I'd
      42             :  * prefer to deal with this here rather than inside the
      43             :  * Kerberos mechanism.
      44             :  */
      45             : gss_OID_desc _gss_spnego_mskrb_mechanism_oid_desc =
      46             :     {9, rk_UNCONST("\x2a\x86\x48\x82\xf7\x12\x01\x02\x02")};
      47             : 
      48             : /*
      49             :  * Allocate a SPNEGO context handle
      50             :  */
      51             : OM_uint32 GSSAPI_CALLCONV
      52           0 : _gss_spnego_alloc_sec_context (OM_uint32 * minor_status,
      53             :                                gss_ctx_id_t *context_handle)
      54             : {
      55           0 :     gssspnego_ctx ctx;
      56             : 
      57           0 :     ctx = calloc(1, sizeof(*ctx));
      58           0 :     if (ctx == NULL) {
      59           0 :         *minor_status = ENOMEM;
      60           0 :         return GSS_S_FAILURE;
      61             :     }
      62             : 
      63           0 :     ctx->NegTokenInit_mech_types.value = NULL;
      64           0 :     ctx->NegTokenInit_mech_types.length = 0;
      65             : 
      66           0 :     ctx->preferred_mech_type = GSS_C_NO_OID;
      67           0 :     ctx->selected_mech_type = GSS_C_NO_OID;
      68           0 :     ctx->negotiated_mech_type = GSS_C_NO_OID;
      69             : 
      70           0 :     ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;
      71             : 
      72           0 :     ctx->mech_flags = 0;
      73           0 :     ctx->mech_time_rec = 0;
      74           0 :     ctx->mech_src_name = GSS_C_NO_NAME;
      75             : 
      76           0 :     ctx->flags.open = 0;
      77           0 :     ctx->flags.local = 0;
      78           0 :     ctx->flags.peer_require_mic = 0;
      79           0 :     ctx->flags.require_mic = 0;
      80           0 :     ctx->flags.verified_mic = 0;
      81             : 
      82           0 :     HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex);
      83             : 
      84           0 :     ctx->negoex_step = 0;
      85           0 :     ctx->negoex_transcript = NULL;
      86           0 :     ctx->negoex_seqnum = 0;
      87           0 :     HEIM_TAILQ_INIT(&ctx->negoex_mechs);
      88           0 :     memset(ctx->negoex_conv_id, 0, GUID_LENGTH);
      89             : 
      90           0 :     *context_handle = (gss_ctx_id_t)ctx;
      91             : 
      92           0 :     return GSS_S_COMPLETE;
      93             : }
      94             : 
      95             : /*
      96             :  * Free a SPNEGO context handle. The caller must have acquired
      97             :  * the lock before this is called.
      98             :  */
      99           0 : OM_uint32 GSSAPI_CALLCONV _gss_spnego_internal_delete_sec_context
     100             :            (OM_uint32 *minor_status,
     101             :             gss_ctx_id_t *context_handle,
     102             :             gss_buffer_t output_token
     103             :            )
     104             : {
     105           0 :     gssspnego_ctx ctx;
     106           0 :     OM_uint32 ret, minor;
     107             : 
     108           0 :     *minor_status = 0;
     109             : 
     110           0 :     if (context_handle == NULL) {
     111           0 :         return GSS_S_NO_CONTEXT;
     112             :     }
     113             : 
     114           0 :     if (output_token != GSS_C_NO_BUFFER) {
     115           0 :         output_token->length = 0;
     116           0 :         output_token->value = NULL;
     117             :     }
     118             : 
     119           0 :     ctx = (gssspnego_ctx)*context_handle;
     120           0 :     *context_handle = GSS_C_NO_CONTEXT;
     121             : 
     122           0 :     if (ctx == NULL) {
     123           0 :         return GSS_S_NO_CONTEXT;
     124             :     }
     125             : 
     126           0 :     if (ctx->NegTokenInit_mech_types.value)
     127           0 :         free(ctx->NegTokenInit_mech_types.value);
     128             : 
     129           0 :     ctx->preferred_mech_type = GSS_C_NO_OID;
     130           0 :     ctx->negotiated_mech_type = GSS_C_NO_OID;
     131           0 :     ctx->selected_mech_type = GSS_C_NO_OID;
     132             : 
     133           0 :     gss_release_name(&minor, &ctx->target_name);
     134           0 :     gss_release_name(&minor, &ctx->mech_src_name);
     135             : 
     136           0 :     if (ctx->negotiated_ctx_id != GSS_C_NO_CONTEXT) {
     137           0 :         ret = gss_delete_sec_context(minor_status,
     138             :                                      &ctx->negotiated_ctx_id,
     139             :                                      output_token);
     140           0 :         ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;
     141             :     } else {
     142           0 :         ret = GSS_S_COMPLETE;
     143             :     }
     144             : 
     145           0 :     _gss_negoex_release_context(ctx);
     146             : 
     147           0 :     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
     148           0 :     HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
     149             : 
     150           0 :     free(ctx);
     151             : 
     152           0 :     return ret;
     153             : }
     154             : 
     155             : static int
     156           0 : inq_context_by_oid_bool(gssspnego_ctx ctx, gss_OID oid)
     157             : {
     158           0 :     OM_uint32 major, minor;
     159           0 :     gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
     160           0 :     uint8_t ret = 0;
     161             : 
     162           0 :     major = gss_inquire_sec_context_by_oid(&minor, ctx->negotiated_ctx_id,
     163             :                                            oid, &data_set);
     164           0 :     if (major != GSS_S_COMPLETE)
     165           0 :         return FALSE;
     166             : 
     167           0 :     if (data_set != GSS_C_NO_BUFFER_SET &&
     168           0 :         data_set->count == 1 &&
     169           0 :         data_set->elements[0].length == 1)
     170           0 :         ret = *((uint8_t *)data_set->elements[0].value);
     171             : 
     172           0 :     gss_release_buffer_set(&minor, &data_set);
     173             : 
     174           0 :     return ret != 0;
     175             : }
     176             : 
     177             : /*
     178             :  * Returns TRUE if it is safe to omit mechListMIC.
     179             :  */
     180             : 
     181             : int
     182           0 : _gss_spnego_safe_omit_mechlist_mic(gssspnego_ctx ctx)
     183             : {
     184           0 :     int safe_omit = FALSE;
     185             : 
     186           0 :     if (ctx->flags.peer_require_mic) {
     187           0 :         _gss_mg_log(10, "spnego: mechListMIC required by peer");
     188           0 :     } else if (inq_context_by_oid_bool(ctx, GSS_C_INQ_PEER_HAS_BUGGY_SPNEGO)) {
     189             :         /* [MS-SPNG] Appendix A <7> Section 3.1.5.1: may be old peer with buggy SPNEGO */
     190           0 :         safe_omit = TRUE;
     191           0 :         _gss_mg_log(10, "spnego: mechListMIC omitted for legacy interoperability");
     192           0 :     } else if (inq_context_by_oid_bool(ctx, GSS_C_INQ_REQUIRE_MECHLIST_MIC)) {
     193             :         /*  [MS-SPNG] Appendix A <7> Section 3.1.5.1: allow NTLM to force MIC */
     194           0 :         _gss_mg_log(10, "spnego: mechListMIC required by mechanism");
     195           0 :     } else if (gss_oid_equal(ctx->selected_mech_type, ctx->preferred_mech_type)) {
     196           0 :         safe_omit = TRUE;
     197           0 :         _gss_mg_log(10, "spnego: mechListMIC omitted as preferred mechanism selected");
     198             :     } else {
     199           0 :         _gss_mg_log(10, "spnego: mechListMIC required by default");
     200             :     }
     201             : 
     202           0 :     return safe_omit;
     203             : }
     204             : 
     205             : /*
     206             :  * A map between a GSS-API flag and a (mechanism attribute, weight)
     207             :  * tuple. The list of mechanisms is re-ordered by aggregate weight
     208             :  * (highest weight is more preferred, e.g. if GSS_C_MUTUAL_FLAG and
     209             :  * GSS_C_ANON_FLAG are set, we prefer a mechanism that supports
     210             :  * mutual authentication over one that only supports anonymous).
     211             :  */
     212             : static struct {
     213             :     OM_uint32 flag;
     214             :     gss_OID ma;
     215             :     int weight;
     216             : } flag_to_ma_map[] = {
     217             :     { GSS_C_MUTUAL_FLAG, GSS_C_MA_AUTH_TARG, 2 },
     218             :     { GSS_C_ANON_FLAG, GSS_C_MA_AUTH_INIT_ANON, 1 },
     219             : };
     220             : 
     221             : /*
     222             :  * Returns a bitmask indicating GSS flags we can sort on.
     223             :  */
     224             : static inline OM_uint32
     225           0 : mech_flag_mask(void)
     226             : {
     227           0 :     size_t i;
     228           0 :     OM_uint32 mask = 0;
     229             : 
     230           0 :     for (i = 0; i < sizeof(flag_to_ma_map)/sizeof(flag_to_ma_map[0]); i++)
     231           0 :         mask |= flag_to_ma_map[i].flag;
     232             : 
     233           0 :     return mask;
     234             : }
     235             : 
     236             : /*
     237             :  * Returns an integer representing the preference weighting for a
     238             :  * mechanism, based on the requested GSS flags.
     239             :  */
     240             : static int
     241           0 : mech_weight(gss_const_OID mech, OM_uint32 req_flags)
     242             : {
     243           0 :     OM_uint32 major, minor;
     244           0 :     gss_OID_set mech_attrs = GSS_C_NO_OID_SET;
     245           0 :     int weight = 0;
     246           0 :     size_t i, j;
     247             : 
     248           0 :     major = gss_inquire_attrs_for_mech(&minor, mech, &mech_attrs, NULL);
     249           0 :     if (GSS_ERROR(major))
     250           0 :         return 0;
     251             : 
     252           0 :     for (i = 0; i < sizeof(flag_to_ma_map)/sizeof(flag_to_ma_map[0]); i++) {
     253           0 :         if ((req_flags & flag_to_ma_map[i].flag) == 0)
     254           0 :             continue;
     255             : 
     256           0 :         for (j = 0; j < mech_attrs->count; j++) {
     257           0 :             if (gss_oid_equal(flag_to_ma_map[i].ma, &mech_attrs->elements[j])) {
     258           0 :                 weight += flag_to_ma_map[i].weight;
     259           0 :                 continue;
     260             :             }
     261             :         }
     262             :     }
     263             : 
     264           0 :     gss_release_oid_set(&minor, &mech_attrs);
     265             : 
     266           0 :     return weight;
     267             : }
     268             : 
     269             : static int
     270           0 : mech_compare(const void *mech1, const void *mech2, void *req_flags_p)
     271             : {
     272           0 :     OM_uint32 req_flags = *((OM_uint32 *)req_flags_p);
     273           0 :     int mech1_weight = mech_weight(mech1, req_flags);
     274           0 :     int mech2_weight = mech_weight(mech2, req_flags);
     275             : 
     276           0 :     return mech2_weight - mech1_weight;
     277             : }
     278             : 
     279             : /*
     280             :  * Order a list of mechanisms by weight based on requested GSS flags.
     281             :  */
     282             : static void
     283           0 : order_mechs_by_flags(gss_OID_set mechs, OM_uint32 req_flags)
     284             : {
     285           0 :     if (req_flags & mech_flag_mask()) { /* skip if flags irrelevant */
     286             :         /*
     287             :          * NB: must be a stable sort to preserve the existing order
     288             :          * of mechanisms that are equally weighted.
     289             :          */
     290           0 :         mergesort_r(mechs->elements, mechs->count,
     291             :                     sizeof(gss_OID_desc), mech_compare, &req_flags);
     292             :     }
     293           0 : }
     294             : 
     295             : static OM_uint32
     296           0 : add_mech_type(OM_uint32 *minor_status,
     297             :               gss_OID mech_type,
     298             :               MechTypeList *mechtypelist)
     299             : {
     300           0 :     MechType mech;
     301           0 :     int ret;
     302             : 
     303           0 :     heim_assert(!gss_oid_equal(mech_type, GSS_SPNEGO_MECHANISM),
     304             :                 "SPNEGO mechanism not filtered");
     305             : 
     306           0 :     ret = der_get_oid(mech_type->elements, mech_type->length, &mech, NULL);
     307           0 :     if (ret == 0) {
     308           0 :         ret = add_MechTypeList(mechtypelist, &mech);
     309           0 :         free_MechType(&mech);
     310             :     }
     311             : 
     312           0 :     if (ret) {
     313           0 :         *minor_status = ret;
     314           0 :         return GSS_S_FAILURE;
     315             :     }
     316             : 
     317           0 :     return GSS_S_COMPLETE;
     318             : }
     319             : 
     320             : static int
     321           0 : add_mech_if_approved(OM_uint32 *minor_status,
     322             :                      gss_const_name_t target_name,
     323             :                      OM_uint32 (*func)(OM_uint32 *, void *, gss_const_name_t, gss_const_cred_id_t, gss_OID),
     324             :                      void *userptr,
     325             :                      int includeMSCompatOID,
     326             :                      gss_const_cred_id_t cred_handle,
     327             :                      MechTypeList *mechtypelist,
     328             :                      gss_OID mech_oid,
     329             :                      gss_OID *first_mech,
     330             :                      OM_uint32 *first_major,
     331             :                      OM_uint32 *first_minor,
     332             :                      int *added_negoex)
     333             : {
     334           0 :     OM_uint32 major, minor;
     335             : 
     336             :     /*
     337             :      * Unapproved mechanisms are ignored, but we capture their result
     338             :      * code in case we didn't find any other mechanisms, in which case
     339             :      * we return that to the caller of _gss_spnego_indicate_mechtypelist().
     340             :      */
     341           0 :     major = (*func)(&minor, userptr, target_name, cred_handle, mech_oid);
     342           0 :     if (major != GSS_S_COMPLETE) {
     343           0 :         if (*first_mech == GSS_C_NO_OID) {
     344           0 :             *first_major = major;
     345           0 :             *first_minor = minor;
     346             :         }
     347           0 :         return GSS_S_COMPLETE;
     348             :     }
     349             : 
     350           0 :     if (_gss_negoex_mech_p(mech_oid)) {
     351           0 :         if (*added_negoex == FALSE) {
     352           0 :             major = add_mech_type(minor_status, GSS_NEGOEX_MECHANISM, mechtypelist);
     353           0 :             if (major != GSS_S_COMPLETE)
     354           0 :                 return major;
     355           0 :             *added_negoex = TRUE;
     356             :         }
     357             : 
     358           0 :         if (*first_mech == GSS_C_NO_OID)
     359           0 :             *first_mech = GSS_NEGOEX_MECHANISM;
     360             : 
     361             :         /* if NegoEx-only mech, we are done */
     362           0 :         if (!_gss_negoex_and_spnego_mech_p(mech_oid))
     363           0 :             return GSS_S_COMPLETE;
     364             :     }
     365             : 
     366           0 :     if (includeMSCompatOID && gss_oid_equal(mech_oid, GSS_KRB5_MECHANISM)) {
     367           0 :         major = add_mech_type(minor_status,
     368             :                               &_gss_spnego_mskrb_mechanism_oid_desc,
     369             :                               mechtypelist);
     370           0 :         if (major != GSS_S_COMPLETE)
     371           0 :             return major;
     372             :     }
     373             : 
     374           0 :     major = add_mech_type(minor_status, mech_oid, mechtypelist);
     375           0 :     if (major != GSS_S_COMPLETE)
     376           0 :         return major;
     377             : 
     378           0 :     if (*first_mech == GSS_C_NO_OID)
     379           0 :         *first_mech = mech_oid;
     380             : 
     381           0 :     return GSS_S_COMPLETE;
     382             : }
     383             : 
     384             : OM_uint32 GSSAPI_CALLCONV
     385           0 : _gss_spnego_indicate_mechtypelist (OM_uint32 *minor_status,
     386             :                                    gss_const_name_t target_name,
     387             :                                    OM_uint32 req_flags,
     388             :                                    OM_uint32 (*func)(OM_uint32 *, void *, gss_const_name_t, gss_const_cred_id_t, gss_OID),
     389             :                                    void *userptr,
     390             :                                    int includeMSCompatOID,
     391             :                                    gss_const_cred_id_t cred_handle,
     392             :                                    MechTypeList *mechtypelist,
     393             :                                    gss_OID *preferred_mech)
     394             : {
     395           0 :     gss_OID_set supported_mechs = GSS_C_NO_OID_SET;
     396           0 :     gss_OID first_mech = GSS_C_NO_OID;
     397           0 :     OM_uint32 ret, minor;
     398           0 :     OM_uint32 first_major = GSS_S_BAD_MECH, first_minor = 0;
     399           0 :     size_t i;
     400           0 :     int added_negoex = FALSE, canonical_order = FALSE;
     401             : 
     402           0 :     mechtypelist->len = 0;
     403           0 :     mechtypelist->val = NULL;
     404             : 
     405           0 :     if (cred_handle != GSS_C_NO_CREDENTIAL)
     406           0 :         ret = _gss_spnego_inquire_cred_mechs(minor_status, cred_handle,
     407             :                                              &supported_mechs, &canonical_order);
     408             :     else
     409           0 :         ret = _gss_spnego_indicate_mechs(minor_status, &supported_mechs);
     410           0 :     if (ret != GSS_S_COMPLETE)
     411           0 :         return ret;
     412             : 
     413           0 :     if (!canonical_order)
     414           0 :         order_mechs_by_flags(supported_mechs, req_flags);
     415             : 
     416           0 :     heim_assert(supported_mechs != GSS_C_NO_OID_SET,
     417             :                 "NULL mech set returned by SPNEGO inquire/indicate mechs");
     418             : 
     419             :     /*
     420             :      * Previously krb5 was tried explicitly, but now the internal mech
     421             :      * list is reordered so that krb5 is first, this should no longer
     422             :      * be required. This permits an application to specify another
     423             :      * mechanism as preferred over krb5 using gss_set_neg_mechs().
     424             :      */
     425           0 :     for (i = 0; i < supported_mechs->count; i++) {
     426           0 :         ret = add_mech_if_approved(minor_status, target_name,
     427             :                                    func, userptr, includeMSCompatOID,
     428             :                                    cred_handle, mechtypelist,
     429           0 :                                    &supported_mechs->elements[i],
     430             :                                    &first_mech,
     431             :                                    &first_major, &first_minor,
     432             :                                    &added_negoex);
     433           0 :         if (ret != GSS_S_COMPLETE) {
     434           0 :             gss_release_oid_set(&minor, &supported_mechs);
     435           0 :             return ret;
     436             :         }
     437             :     }
     438             : 
     439           0 :     heim_assert(mechtypelist->len == 0 || first_mech != GSS_C_NO_OID,
     440             :                 "mechtypelist non-empty but no mech selected");
     441             : 
     442           0 :     if (first_mech != GSS_C_NO_OID)
     443           0 :         ret = _gss_intern_oid(minor_status, first_mech, &first_mech);
     444           0 :     else if (GSS_ERROR(first_major)) {
     445           0 :         ret = first_major;
     446           0 :         *minor_status = first_minor;
     447             :     } else
     448           0 :         ret = GSS_S_BAD_MECH;
     449             : 
     450           0 :     if (preferred_mech != NULL)
     451           0 :         *preferred_mech = first_mech;
     452             : 
     453           0 :     gss_release_oid_set(&minor, &supported_mechs);
     454             : 
     455           0 :     return ret;
     456             : }
     457             : 
     458             : /*
     459             :  *
     460             :  */
     461             : 
     462             : OM_uint32
     463           0 : _gss_spnego_verify_mechtypes_mic(OM_uint32 *minor_status,
     464             :                                  gssspnego_ctx ctx,
     465             :                                  heim_octet_string *mic)
     466             : {
     467           0 :     gss_buffer_desc mic_buf;
     468           0 :     OM_uint32 major_status;
     469             : 
     470           0 :     if (mic == NULL) {
     471           0 :         *minor_status = 0;
     472           0 :         return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM,
     473             :                                        GSS_S_DEFECTIVE_TOKEN, 0,
     474             :                                        "SPNEGO peer failed to send mechListMIC");
     475             :     }
     476             : 
     477           0 :     if (ctx->flags.verified_mic) {
     478             :         /* This doesn't make sense, we've already verified it? */
     479           0 :         *minor_status = 0;
     480           0 :         return GSS_S_DUPLICATE_TOKEN;
     481             :     }
     482             : 
     483           0 :     mic_buf.length = mic->length;
     484           0 :     mic_buf.value  = mic->data;
     485             : 
     486           0 :     major_status = gss_verify_mic(minor_status,
     487           0 :                                   ctx->negotiated_ctx_id,
     488           0 :                                   &ctx->NegTokenInit_mech_types,
     489             :                                   &mic_buf,
     490             :                                   NULL);
     491           0 :     if (major_status == GSS_S_COMPLETE) {
     492           0 :         _gss_spnego_ntlm_reset_crypto(minor_status, ctx, TRUE);
     493           0 :     } else if (major_status == GSS_S_UNAVAILABLE) {
     494           0 :         _gss_mg_log(10, "mech doesn't support MIC, allowing anyway"); 
     495           0 :     } else if (major_status) {
     496           0 :         return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM,
     497             :                                        GSS_S_DEFECTIVE_TOKEN, *minor_status,
     498             :                                        "SPNEGO peer sent invalid mechListMIC");
     499             :     }
     500           0 :     ctx->flags.verified_mic = 1;
     501             : 
     502           0 :     *minor_status = 0;
     503             : 
     504           0 :     return GSS_S_COMPLETE;
     505             : }
     506             : 
     507             : /*
     508             :  * According to [MS-SPNG] 3.3.5.1 the crypto state for NTLM is reset
     509             :  * before the completed context is returned to the application.
     510             :  */
     511             : 
     512             : OM_uint32
     513           0 : _gss_spnego_ntlm_reset_crypto(OM_uint32 *minor_status,
     514             :                               gssspnego_ctx ctx,
     515             :                               OM_uint32 verify)
     516             : {
     517           0 :     if (gss_oid_equal(ctx->negotiated_mech_type, GSS_NTLM_MECHANISM)) {
     518           0 :         gss_buffer_desc value;
     519             : 
     520           0 :         value.length = sizeof(verify);
     521           0 :         value.value = &verify;
     522             : 
     523           0 :         return gss_set_sec_context_option(minor_status,
     524             :                                           &ctx->negotiated_ctx_id,
     525             :                                           GSS_C_NTLM_RESET_CRYPTO,
     526             :                                           &value);
     527             :     }
     528             : 
     529           0 :     return GSS_S_COMPLETE;
     530             : }
     531             : 
     532             : void
     533           0 : _gss_spnego_log_mech(const char *prefix, gss_const_OID oid)
     534             : {
     535           0 :     gss_buffer_desc oidbuf = GSS_C_EMPTY_BUFFER;
     536           0 :     OM_uint32 junk;
     537           0 :     const char *name = NULL;
     538             : 
     539           0 :     if (!_gss_mg_log_level(10))
     540           0 :         return;
     541             : 
     542           0 :     if (oid == GSS_C_NO_OID ||
     543           0 :         gss_oid_to_str(&junk, (gss_OID)oid, &oidbuf) != GSS_S_COMPLETE) {
     544           0 :         _gss_mg_log(10, "spnego: %s (null)", prefix);
     545           0 :         return;
     546             :     }
     547             : 
     548           0 :     if (gss_oid_equal(oid, GSS_NEGOEX_MECHANISM))
     549           0 :         name = "negoex"; /* not a real mech */
     550           0 :     else if (gss_oid_equal(oid, &_gss_spnego_mskrb_mechanism_oid_desc))
     551           0 :         name = "mskrb";
     552             :     else {
     553           0 :         gssapi_mech_interface m = __gss_get_mechanism(oid);
     554           0 :         if (m)
     555           0 :             name = m->gm_name;
     556             :     }
     557             : 
     558           0 :     _gss_mg_log(10, "spnego: %s %s { %.*s }",
     559             :                 prefix,
     560             :                 name ? name : "unknown",
     561           0 :                 (int)oidbuf.length, (char *)oidbuf.value);
     562           0 :     gss_release_buffer(&junk, &oidbuf);
     563             : }
     564             : 
     565             : void
     566           0 : _gss_spnego_log_mechTypes(MechTypeList *mechTypes)
     567             : {
     568           0 :     size_t i;
     569           0 :     char mechbuf[64];
     570           0 :     size_t mech_len;
     571           0 :     gss_OID_desc oid;
     572           0 :     int ret;
     573             : 
     574           0 :     if (!_gss_mg_log_level(10))
     575           0 :         return;
     576             : 
     577           0 :     for (i = 0; i < mechTypes->len; i++) {
     578           0 :         ret = der_put_oid ((unsigned char *)mechbuf + sizeof(mechbuf) - 1,
     579             :                            sizeof(mechbuf),
     580           0 :                            &mechTypes->val[i],
     581             :                            &mech_len);
     582           0 :         if (ret)
     583           0 :             continue;
     584             : 
     585           0 :         oid.length   = (OM_uint32)mech_len;
     586           0 :         oid.elements = mechbuf + sizeof(mechbuf) - mech_len;
     587             : 
     588           0 :         _gss_spnego_log_mech("initiator proposed mech", &oid);
     589             :     }
     590             : }
     591             : 
     592             : /*
     593             :  * Indicate mechs negotiable by SPNEGO
     594             :  */
     595             : 
     596             : OM_uint32
     597           0 : _gss_spnego_indicate_mechs(OM_uint32 *minor_status,
     598             :                            gss_OID_set *mechs_p)
     599             : {
     600           0 :     gss_OID_desc oids[3];
     601           0 :     gss_OID_set_desc except;
     602             : 
     603           0 :     *mechs_p = GSS_C_NO_OID_SET;
     604             : 
     605           0 :     oids[0] = *GSS_C_MA_DEPRECATED;
     606           0 :     oids[1] = *GSS_C_MA_NOT_DFLT_MECH;
     607           0 :     oids[2] = *GSS_C_MA_MECH_NEGO;
     608             : 
     609           0 :     except.count = sizeof(oids) / sizeof(oids[0]);
     610           0 :     except.elements = oids;
     611             : 
     612           0 :     return gss_indicate_mechs_by_attrs(minor_status,
     613             :                                        GSS_C_NO_OID_SET,
     614             :                                        &except,
     615             :                                        GSS_C_NO_OID_SET,
     616             :                                        mechs_p);
     617             : }
     618             : 
     619             : /*
     620             :  * Indicate mechs in cred negotiatble by SPNEGO
     621             :  */
     622             : 
     623             : OM_uint32
     624           0 : _gss_spnego_inquire_cred_mechs(OM_uint32 *minor_status,
     625             :                                gss_const_cred_id_t cred,
     626             :                                gss_OID_set *mechs_p,
     627             :                                int *canonical_order)
     628             : {
     629           0 :     OM_uint32 ret, junk;
     630           0 :     gss_OID_set cred_mechs = GSS_C_NO_OID_SET;
     631           0 :     gss_OID_set negotiable_mechs = GSS_C_NO_OID_SET;
     632           0 :     size_t i;
     633             : 
     634           0 :     *mechs_p = GSS_C_NO_OID_SET;
     635           0 :     *canonical_order = FALSE;
     636             : 
     637           0 :     heim_assert(cred != GSS_C_NO_CREDENTIAL, "Invalid null credential handle");
     638             : 
     639           0 :     ret = gss_get_neg_mechs(minor_status, cred, &cred_mechs);
     640           0 :     if (ret == GSS_S_COMPLETE) {
     641           0 :         *canonical_order = TRUE;
     642             :     } else {
     643           0 :         ret = gss_inquire_cred(minor_status, cred, NULL, NULL, NULL, &cred_mechs);
     644           0 :         if (ret != GSS_S_COMPLETE)
     645           0 :             goto out;
     646             :     }
     647             : 
     648           0 :     heim_assert(cred_mechs != GSS_C_NO_OID_SET && cred_mechs->count > 0,
     649             :                 "gss_inquire_cred succeeded but returned no mechanisms");
     650             : 
     651           0 :     ret = _gss_spnego_indicate_mechs(minor_status, &negotiable_mechs);
     652           0 :     if (ret != GSS_S_COMPLETE)
     653           0 :         goto out;
     654             : 
     655           0 :     heim_assert(negotiable_mechs != GSS_C_NO_OID_SET,
     656             :                 "_gss_spnego_indicate_mechs succeeded but returned null OID set");
     657             : 
     658           0 :     ret = gss_create_empty_oid_set(minor_status, mechs_p);
     659           0 :     if (ret != GSS_S_COMPLETE)
     660           0 :         goto out;
     661             : 
     662             :     /* Filter credential mechs by negotiable mechs, order by credential mechs */
     663           0 :     for (i = 0; i < cred_mechs->count; i++) {
     664           0 :         gss_OID cred_mech = &cred_mechs->elements[i];
     665           0 :         int present = 0;
     666             : 
     667           0 :         gss_test_oid_set_member(&junk, cred_mech, negotiable_mechs, &present);
     668           0 :         if (!present)
     669           0 :             continue;
     670             : 
     671           0 :         ret = gss_add_oid_set_member(minor_status, cred_mech, mechs_p);
     672           0 :         if (ret != GSS_S_COMPLETE)
     673           0 :             break;
     674             :     }
     675             : 
     676           0 : out:
     677           0 :     if (ret != GSS_S_COMPLETE)
     678           0 :         gss_release_oid_set(&junk, mechs_p);
     679           0 :     gss_release_oid_set(&junk, &cred_mechs);
     680           0 :     gss_release_oid_set(&junk, &negotiable_mechs);
     681             : 
     682           0 :     return ret;
     683             : }
     684             : 

Generated by: LCOV version 1.14