LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/gssapi/spnego - accept_sec_context.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 0 493 0.0 %
Date: 2024-04-13 12:30:31 Functions: 0 11 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * Portions Copyright (c) 2004 PADL Software Pty Ltd.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  *
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer.
      12             :  *
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  *
      17             :  * 3. Neither the name of the Institute nor the names of its contributors
      18             :  *    may be used to endorse or promote products derived from this software
      19             :  *    without specific prior written permission.
      20             :  *
      21             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      22             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      23             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      24             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      25             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      26             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      27             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      29             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      30             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      31             :  * SUCH DAMAGE.
      32             :  */
      33             : 
      34             : #include "spnego_locl.h"
      35             : 
      36             : static OM_uint32
      37           0 : send_reject (OM_uint32 *minor_status,
      38             :              gss_const_buffer_t mech_token,
      39             :              gss_buffer_t output_token)
      40             : {
      41           0 :     NegotiationToken nt;
      42           0 :     size_t size;
      43           0 :     heim_octet_string responseToken;
      44             : 
      45           0 :     nt.element = choice_NegotiationToken_negTokenResp;
      46             : 
      47           0 :     ALLOC(nt.u.negTokenResp.negState, 1);
      48           0 :     if (nt.u.negTokenResp.negState == NULL) {
      49           0 :         *minor_status = ENOMEM;
      50           0 :         return GSS_S_FAILURE;
      51             :     }
      52           0 :     *(nt.u.negTokenResp.negState)  = reject;
      53           0 :     nt.u.negTokenResp.supportedMech = NULL;
      54           0 :     nt.u.negTokenResp.responseToken = NULL;
      55             : 
      56           0 :     if (mech_token != GSS_C_NO_BUFFER && mech_token->value != NULL) {
      57           0 :         responseToken.length = mech_token->length;
      58           0 :         responseToken.data   = mech_token->value;
      59           0 :         nt.u.negTokenResp.responseToken = &responseToken;
      60             :      } else
      61           0 :         nt.u.negTokenResp.responseToken = NULL;
      62           0 :     nt.u.negTokenResp.mechListMIC   = NULL;
      63             : 
      64           0 :     ASN1_MALLOC_ENCODE(NegotiationToken,
      65             :                        output_token->value, output_token->length, &nt,
      66             :                        &size, *minor_status);
      67           0 :     nt.u.negTokenResp.responseToken = NULL; /* allocated on stack */
      68           0 :     free_NegotiationToken(&nt);
      69           0 :     if (*minor_status != 0)
      70           0 :         return GSS_S_FAILURE;
      71             : 
      72           0 :     return GSS_S_BAD_MECH;
      73             : }
      74             : 
      75             : static OM_uint32
      76           0 : acceptor_approved(OM_uint32 *minor_status,
      77             :                   void *userptr,
      78             :                   gss_const_name_t target_name,
      79             :                   gss_const_cred_id_t cred_handle,
      80             :                   gss_OID mech)
      81             : {
      82           0 :     gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
      83           0 :     gss_OID_set oidset = GSS_C_NO_OID_SET;
      84           0 :     OM_uint32 junk, ret;
      85             : 
      86           0 :     if (target_name == GSS_C_NO_NAME)
      87           0 :         return GSS_S_COMPLETE;
      88             : 
      89           0 :     if (gss_oid_equal(mech, GSS_NEGOEX_MECHANISM)) {
      90           0 :         size_t i;
      91             : 
      92           0 :         ret = _gss_spnego_indicate_mechs(minor_status, &oidset);
      93           0 :         if (ret != GSS_S_COMPLETE)
      94           0 :             return ret;
      95             : 
      96             :         /* before committing to NegoEx, check we can negotiate a mech */
      97           0 :         for (i = 0; i < oidset->count; i++) {
      98           0 :             gss_OID inner_mech = &oidset->elements[i];
      99             : 
     100           0 :             if (_gss_negoex_mech_p(inner_mech)) {
     101           0 :                 ret = acceptor_approved(minor_status, userptr,
     102             :                                         target_name, cred_handle,
     103             :                                         inner_mech);
     104           0 :                 if (ret == GSS_S_COMPLETE)
     105           0 :                     break;
     106             :             }
     107             :         }
     108           0 :     } else if (cred_handle != GSS_C_NO_CREDENTIAL) {
     109           0 :         ret = gss_inquire_cred_by_mech(minor_status, cred_handle, mech,
     110             :                                        NULL, NULL, NULL, NULL);
     111             :     } else {
     112           0 :         ret = gss_create_empty_oid_set(minor_status, &oidset);
     113           0 :         if (ret == GSS_S_COMPLETE)
     114           0 :             ret = gss_add_oid_set_member(minor_status, mech, &oidset);
     115           0 :         if (ret == GSS_S_COMPLETE)
     116           0 :             ret = gss_acquire_cred(minor_status, target_name,
     117             :                                    GSS_C_INDEFINITE, oidset,
     118             :                                GSS_C_ACCEPT, &cred, NULL, NULL);
     119             :     }
     120             : 
     121           0 :     gss_release_oid_set(&junk, &oidset);
     122           0 :     gss_release_cred(&junk, &cred);
     123             : 
     124           0 :     return ret;
     125             : }
     126             : 
     127             : static OM_uint32
     128           0 : send_supported_mechs (OM_uint32 *minor_status,
     129             :                       gssspnego_ctx ctx,
     130             :                       gss_const_cred_id_t acceptor_cred,
     131             :                       gss_buffer_t output_token)
     132             : {
     133           0 :     NegotiationToken2 nt;
     134           0 :     size_t buf_len = 0;
     135           0 :     gss_buffer_desc data;
     136           0 :     OM_uint32 ret;
     137             : 
     138           0 :     memset(&nt, 0, sizeof(nt));
     139             : 
     140           0 :     nt.element = choice_NegotiationToken2_negTokenInit;
     141           0 :     nt.u.negTokenInit.reqFlags = NULL;
     142           0 :     nt.u.negTokenInit.mechToken = NULL;
     143           0 :     nt.u.negTokenInit.negHints = NULL;
     144             : 
     145           0 :     ret = _gss_spnego_indicate_mechtypelist(minor_status, GSS_C_NO_NAME, 0,
     146             :                                             acceptor_approved, ctx, 1, acceptor_cred,
     147             :                                             &nt.u.negTokenInit.mechTypes, NULL);
     148           0 :     if (ret != GSS_S_COMPLETE) {
     149           0 :         return ret;
     150             :     }
     151             : 
     152           0 :     ALLOC(nt.u.negTokenInit.negHints, 1);
     153           0 :     if (nt.u.negTokenInit.negHints == NULL) {
     154           0 :         *minor_status = ENOMEM;
     155           0 :         free_NegotiationToken2(&nt);
     156           0 :         return GSS_S_FAILURE;
     157             :     }
     158             : 
     159           0 :     ALLOC(nt.u.negTokenInit.negHints->hintName, 1);
     160           0 :     if (nt.u.negTokenInit.negHints->hintName == NULL) {
     161           0 :         *minor_status = ENOMEM;
     162           0 :         free_NegotiationToken2(&nt);
     163           0 :         return GSS_S_FAILURE;
     164             :     }
     165             : 
     166           0 :     *nt.u.negTokenInit.negHints->hintName = strdup("not_defined_in_RFC4178@please_ignore");
     167           0 :     nt.u.negTokenInit.negHints->hintAddress = NULL;
     168             : 
     169           0 :     ASN1_MALLOC_ENCODE(NegotiationToken2,
     170             :                        data.value, data.length, &nt, &buf_len, ret);
     171           0 :     free_NegotiationToken2(&nt);
     172           0 :     if (ret) {
     173           0 :         *minor_status = ret;
     174           0 :         return GSS_S_FAILURE;
     175             :     }
     176           0 :     if (data.length != buf_len) {
     177           0 :         abort();
     178           0 :         UNREACHABLE(return GSS_S_FAILURE);
     179             :     }
     180             : 
     181           0 :     ret = gss_encapsulate_token(&data, GSS_SPNEGO_MECHANISM, output_token);
     182             : 
     183           0 :     free (data.value);
     184             : 
     185           0 :     if (ret != GSS_S_COMPLETE)
     186           0 :         return ret;
     187             : 
     188           0 :     *minor_status = 0;
     189             : 
     190           0 :     return GSS_S_CONTINUE_NEEDED;
     191             : }
     192             : 
     193             : static OM_uint32
     194           0 : send_accept (OM_uint32 *minor_status,
     195             :              gssspnego_ctx context_handle,
     196             :              int optimistic_mech_ok,
     197             :              gss_buffer_t mech_token,
     198             :              gss_const_OID selected_mech, /* valid on initial response only */
     199             :              gss_buffer_t mech_buf,
     200             :              gss_buffer_t output_token)
     201             : {
     202           0 :     int initial_response = (selected_mech != GSS_C_NO_OID);
     203           0 :     NegotiationToken nt;
     204           0 :     OM_uint32 ret, minor;
     205           0 :     gss_buffer_desc mech_mic_buf;
     206           0 :     size_t size;
     207             : 
     208           0 :     memset(&nt, 0, sizeof(nt));
     209             : 
     210           0 :     nt.element = choice_NegotiationToken_negTokenResp;
     211             : 
     212           0 :     ALLOC(nt.u.negTokenResp.negState, 1);
     213           0 :     if (nt.u.negTokenResp.negState == NULL) {
     214           0 :         *minor_status = ENOMEM;
     215           0 :         return GSS_S_FAILURE;
     216             :     }
     217             : 
     218           0 :     if (context_handle->flags.open) {
     219           0 :         if (mech_token != GSS_C_NO_BUFFER
     220           0 :             && mech_token->length != 0
     221           0 :             && mech_buf != GSS_C_NO_BUFFER)
     222           0 :             *(nt.u.negTokenResp.negState)  = accept_incomplete;
     223             :         else
     224           0 :             *(nt.u.negTokenResp.negState)  = accept_completed;
     225             :     } else {
     226           0 :         if (initial_response && !optimistic_mech_ok)
     227           0 :             *(nt.u.negTokenResp.negState)  = request_mic;
     228             :         else
     229           0 :             *(nt.u.negTokenResp.negState)  = accept_incomplete;
     230             :     }
     231             : 
     232           0 :     if (initial_response) {
     233           0 :         ALLOC(nt.u.negTokenResp.supportedMech, 1);
     234           0 :         if (nt.u.negTokenResp.supportedMech == NULL) {
     235           0 :             *minor_status = ENOMEM;
     236           0 :             ret = GSS_S_FAILURE;
     237           0 :             goto out;
     238             :         }
     239             : 
     240           0 :         ret = der_get_oid(selected_mech->elements,
     241           0 :                           selected_mech->length,
     242           0 :                           nt.u.negTokenResp.supportedMech,
     243             :                           NULL);
     244           0 :         if (ret) {
     245           0 :             *minor_status = ENOMEM;
     246           0 :             ret = GSS_S_FAILURE;
     247           0 :             goto out;
     248             :         }
     249             : 
     250           0 :         _gss_spnego_log_mech("acceptor sending selected mech", selected_mech);
     251             :     } else {
     252           0 :         nt.u.negTokenResp.supportedMech = NULL;
     253             :     }
     254             : 
     255           0 :     if (mech_token != GSS_C_NO_BUFFER && mech_token->length != 0) {
     256           0 :         ALLOC(nt.u.negTokenResp.responseToken, 1);
     257           0 :         if (nt.u.negTokenResp.responseToken == NULL) {
     258           0 :             *minor_status = ENOMEM;
     259           0 :             ret = GSS_S_FAILURE;
     260           0 :             goto out;
     261             :         }
     262           0 :         nt.u.negTokenResp.responseToken->length = mech_token->length;
     263           0 :         nt.u.negTokenResp.responseToken->data   = mech_token->value;
     264           0 :         mech_token->length = 0;
     265           0 :         mech_token->value  = NULL;
     266             :     } else {
     267           0 :         nt.u.negTokenResp.responseToken = NULL;
     268             :     }
     269             : 
     270           0 :     if (mech_buf != GSS_C_NO_BUFFER) {
     271           0 :         ret = gss_get_mic(minor_status,
     272           0 :                           context_handle->negotiated_ctx_id,
     273             :                           0,
     274             :                           mech_buf,
     275             :                           &mech_mic_buf);
     276           0 :         if (ret == GSS_S_COMPLETE) {
     277           0 :             _gss_spnego_ntlm_reset_crypto(&minor, context_handle, FALSE);
     278             : 
     279           0 :             ALLOC(nt.u.negTokenResp.mechListMIC, 1);
     280           0 :             if (nt.u.negTokenResp.mechListMIC == NULL) {
     281           0 :                 gss_release_buffer(minor_status, &mech_mic_buf);
     282           0 :                 *minor_status = ENOMEM;
     283           0 :                 ret = GSS_S_FAILURE;
     284           0 :                 goto out;
     285             :             }
     286           0 :             nt.u.negTokenResp.mechListMIC->length = mech_mic_buf.length;
     287           0 :             nt.u.negTokenResp.mechListMIC->data   = mech_mic_buf.value;
     288           0 :         } else if (ret == GSS_S_UNAVAILABLE) {
     289           0 :             nt.u.negTokenResp.mechListMIC = NULL;
     290             :         } else {
     291           0 :             goto out;
     292             :         }
     293             : 
     294             :     } else
     295           0 :         nt.u.negTokenResp.mechListMIC = NULL;
     296             : 
     297           0 :     ASN1_MALLOC_ENCODE(NegotiationToken,
     298             :                        output_token->value, output_token->length,
     299             :                        &nt, &size, ret);
     300           0 :     if (ret) {
     301           0 :         *minor_status = ENOMEM;
     302           0 :         ret = GSS_S_FAILURE;
     303           0 :         goto out;
     304             :     }
     305             : 
     306             :     /*
     307             :      * The response should not be encapsulated, because
     308             :      * it is a SubsequentContextToken (note though RFC 1964
     309             :      * specifies encapsulation for all _Kerberos_ tokens).
     310             :      */
     311             : 
     312           0 :     if (*(nt.u.negTokenResp.negState) == accept_completed)
     313           0 :         ret = GSS_S_COMPLETE;
     314             :     else
     315           0 :         ret = GSS_S_CONTINUE_NEEDED;
     316             : 
     317           0 :  out:
     318           0 :     free_NegotiationToken(&nt);
     319           0 :     return ret;
     320             : }
     321             : 
     322             : /*
     323             :  * Return the default acceptor identity based on the local hostname
     324             :  * or the GSSAPI_SPNEGO_NAME environment variable.
     325             :  */
     326             : 
     327             : static OM_uint32
     328           0 : default_acceptor_name(OM_uint32 *minor_status,
     329             :                       gss_name_t *namep)
     330             : {
     331           0 :     OM_uint32 major_status;
     332           0 :     gss_buffer_desc namebuf;
     333           0 :     char *str = NULL, *host, hostname[MAXHOSTNAMELEN];
     334             : 
     335           0 :     *namep = GSS_C_NO_NAME;
     336             : 
     337           0 :     host = secure_getenv("GSSAPI_SPNEGO_NAME");
     338           0 :     if (host == NULL) {
     339           0 :         int rv;
     340             : 
     341           0 :         if (gethostname(hostname, sizeof(hostname)) != 0) {
     342           0 :             *minor_status = errno;
     343           0 :             return GSS_S_FAILURE;
     344             :         }
     345             : 
     346           0 :         rv = asprintf(&str, "host@%s", hostname);
     347           0 :         if (rv < 0 || str == NULL) {
     348           0 :             *minor_status = ENOMEM;
     349           0 :             return GSS_S_FAILURE;
     350             :         }
     351           0 :         host = str;
     352             :     }
     353             : 
     354           0 :     namebuf.length = strlen(host);
     355           0 :     namebuf.value = host;
     356             : 
     357           0 :     major_status = gss_import_name(minor_status, &namebuf,
     358             :                                    GSS_C_NT_HOSTBASED_SERVICE, namep);
     359             : 
     360           0 :     free(str);
     361             : 
     362           0 :     return major_status;
     363             : }
     364             : 
     365             : /*
     366             :  * Determine whether the mech in mechType can be negotiated. If the
     367             :  * mech is NegoEx, make NegoEx mechanisms available for negotiation.
     368             :  */
     369             : 
     370             : static OM_uint32
     371           0 : select_mech(OM_uint32 *minor_status,
     372             :             gssspnego_ctx ctx,
     373             :             gss_const_cred_id_t cred,
     374             :             gss_const_OID_set supported_mechs,
     375             :             MechType *mechType,
     376             :             int verify_p, /* set on non-optimistic tokens */
     377             :             gss_const_OID *advertised_mech_p)
     378             : {
     379           0 :     char mechbuf[64];
     380           0 :     size_t mech_len;
     381           0 :     gss_OID_desc oid;
     382           0 :     gss_OID selected_mech = GSS_C_NO_OID;
     383           0 :     OM_uint32 ret, junk;
     384           0 :     int negoex_proposed = FALSE, negoex_selected = FALSE;
     385           0 :     int includeMSCompatOID = FALSE;
     386           0 :     size_t i;
     387             : 
     388           0 :     *minor_status = 0;
     389           0 :     *advertised_mech_p = GSS_C_NO_OID; /* deals with broken MS OID */
     390             : 
     391           0 :     ctx->selected_mech_type = GSS_C_NO_OID;
     392             : 
     393           0 :     ret = der_put_oid ((unsigned char *)mechbuf + sizeof(mechbuf) - 1,
     394             :                        sizeof(mechbuf),
     395             :                        mechType,
     396             :                        &mech_len);
     397           0 :     if (ret)
     398           0 :         return GSS_S_DEFECTIVE_TOKEN;
     399             : 
     400           0 :     oid.length   = (OM_uint32)mech_len;
     401           0 :     oid.elements = mechbuf + sizeof(mechbuf) - mech_len;
     402             : 
     403           0 :     if (gss_oid_equal(&oid, GSS_NEGOEX_MECHANISM))
     404           0 :         negoex_proposed = TRUE;
     405           0 :     else if (gss_oid_equal(&oid, &_gss_spnego_mskrb_mechanism_oid_desc))
     406           0 :         includeMSCompatOID = TRUE;
     407             : 
     408           0 :     for (i = 0; i < supported_mechs->count; i++) {
     409           0 :         gss_OID iter = &supported_mechs->elements[i];
     410           0 :         auth_scheme scheme;
     411           0 :         int is_negoex_mech = /* mechanism is negotiable under NegoEx */
     412           0 :             gssspi_query_mechanism_info(&junk, iter, scheme) == GSS_S_COMPLETE;
     413             : 
     414           0 :         if (is_negoex_mech && negoex_proposed) {
     415           0 :             ret = _gss_negoex_add_auth_mech(minor_status, ctx, iter, scheme);
     416           0 :             if (ret != GSS_S_COMPLETE)
     417           0 :                 break;
     418             : 
     419           0 :             negoex_selected = TRUE;
     420             :         }
     421             : 
     422           0 :         if (gss_oid_equal(includeMSCompatOID ? GSS_KRB5_MECHANISM : &oid, iter)) {
     423           0 :             ret = _gss_intern_oid(minor_status, iter, &selected_mech);
     424           0 :             if (ret != GSS_S_COMPLETE)
     425           0 :                 return ret;
     426             : 
     427           0 :             break;
     428             :         }
     429             :     }
     430             : 
     431             :     /* always prefer NegoEx if a mechanism supported both */
     432           0 :     if (negoex_selected)
     433           0 :         selected_mech = GSS_NEGOEX_MECHANISM;
     434           0 :     if (selected_mech == GSS_C_NO_OID)
     435           0 :         ret = GSS_S_BAD_MECH;
     436           0 :     if (ret != GSS_S_COMPLETE)
     437           0 :         return ret;
     438             : 
     439           0 :     heim_assert(!gss_oid_equal(selected_mech, GSS_SPNEGO_MECHANISM),
     440             :                 "SPNEGO should not be able to negotiate itself");
     441             : 
     442           0 :     if (verify_p) {
     443           0 :         gss_name_t name = GSS_C_NO_NAME;
     444             : 
     445             :         /*
     446             :          * If we do not have a credential, acquire a default name as a hint
     447             :          * to acceptor_approved() so it can attempt to acquire a default
     448             :          * credential.
     449             :          */
     450           0 :         if (cred == GSS_C_NO_CREDENTIAL) {
     451           0 :             ret = default_acceptor_name(minor_status, &name);
     452           0 :             if (ret != GSS_S_COMPLETE)
     453           0 :                 return ret;
     454             :         }
     455             : 
     456           0 :         ret = acceptor_approved(minor_status, ctx, name, cred, selected_mech);
     457             : 
     458           0 :         gss_release_name(&junk, &name);
     459             :     } else {
     460             :         /* Stash optimistic mech for use by _gss_spnego_require_mechlist_mic() */
     461           0 :         ret = gss_duplicate_oid(minor_status, &oid, &ctx->preferred_mech_type);
     462             :     }
     463             : 
     464           0 :     if (ret == GSS_S_COMPLETE) {
     465           0 :         *minor_status = 0;
     466             : 
     467           0 :         *advertised_mech_p = ctx->selected_mech_type = selected_mech;
     468             : 
     469             :         /* if the initiator used the broken MS OID, send that instead */
     470           0 :         if (includeMSCompatOID && gss_oid_equal(selected_mech, GSS_KRB5_MECHANISM))
     471           0 :             *advertised_mech_p = &_gss_spnego_mskrb_mechanism_oid_desc;
     472             :     }
     473             : 
     474           0 :     return ret;
     475             : }
     476             : 
     477             : 
     478             : static OM_uint32
     479           0 : acceptor_complete(OM_uint32 * minor_status,
     480             :                   gssspnego_ctx ctx,
     481             :                   int *get_mic,
     482             :                   gss_buffer_t mech_input_token,
     483             :                   gss_buffer_t mech_output_token,
     484             :                   heim_octet_string *mic,
     485             :                   gss_buffer_t output_token)
     486             : {
     487           0 :     gss_buffer_desc buf = GSS_C_EMPTY_BUFFER;
     488           0 :     OM_uint32 ret;
     489           0 :     int verify_mic;
     490             : 
     491           0 :     ctx->flags.require_mic = 1;
     492           0 :     ctx->flags.safe_omit = _gss_spnego_safe_omit_mechlist_mic(ctx);
     493             : 
     494           0 :     if (ctx->flags.open) {
     495           0 :         if (mech_input_token == GSS_C_NO_BUFFER) { /* Even/One */
     496           0 :             verify_mic = 1;
     497           0 :             *get_mic = 0;
     498           0 :         } else if (mech_output_token != GSS_C_NO_BUFFER &&
     499           0 :                    mech_output_token->length == 0) { /* Odd */
     500           0 :             *get_mic = verify_mic = 1;
     501             :         } else { /* Even/One */
     502           0 :             verify_mic = 0;
     503           0 :             *get_mic = 1;
     504             :         }
     505             : 
     506             :         /*
     507             :          * Change from previous versions: do not generate a MIC if not
     508             :          * necessary. This conforms to RFC4178 s.5 ("if the accepted
     509             :          * mechanism is the most preferred mechanism of both the initiator
     510             :          * and acceptor, then the MIC token exchange... is OPTIONAL"),
     511             :          * and is consistent with MIT and Windows behavior.
     512             :          */
     513           0 :         if (ctx->flags.safe_omit)
     514           0 :             *get_mic = 0;
     515             : 
     516           0 :         if (verify_mic && mic == NULL && ctx->flags.safe_omit) {
     517             :             /*
     518             :              * Peer is old and didn't send a mic while we expected
     519             :              * one, but since it safe to omit, let do that
     520             :              */
     521           0 :         } else if (verify_mic) {
     522           0 :             ret = _gss_spnego_verify_mechtypes_mic(minor_status, ctx, mic);
     523           0 :             if (ret) {
     524           0 :                 if (*get_mic)
     525           0 :                     send_reject(minor_status, GSS_C_NO_BUFFER, output_token);
     526           0 :                 if (buf.value)
     527           0 :                     free(buf.value);
     528           0 :                 return ret;
     529             :             }
     530             :         }
     531             :     } else
     532           0 :         *get_mic = 0;
     533             : 
     534           0 :     return GSS_S_COMPLETE;
     535             : }
     536             : 
     537             : /*
     538             :  * Call gss_accept_sec_context() via mechglue or NegoEx, depending on
     539             :  * whether mech_oid is NegoEx.
     540             :  */
     541             : 
     542             : static OM_uint32
     543           0 : mech_accept(OM_uint32 *minor_status,
     544             :             gssspnego_ctx ctx,
     545             :             gss_const_cred_id_t acceptor_cred_handle,
     546             :             gss_const_buffer_t input_token_buffer,
     547             :             const gss_channel_bindings_t input_chan_bindings,
     548             :             gss_buffer_t output_token,
     549             :             gss_cred_id_t *delegated_cred_handle)
     550             : {
     551           0 :     OM_uint32 ret, junk;
     552             : 
     553           0 :     heim_assert(ctx->selected_mech_type != GSS_C_NO_OID,
     554             :                 "mech_accept called with no selected mech");
     555             : 
     556           0 :     if (gss_oid_equal(ctx->selected_mech_type, GSS_NEGOEX_MECHANISM)) {
     557           0 :         ret = _gss_negoex_accept(minor_status,
     558             :                                  ctx,
     559             :                                  (gss_cred_id_t)acceptor_cred_handle,
     560             :                                  input_token_buffer,
     561             :                                  input_chan_bindings,
     562             :                                  output_token,
     563             :                                  delegated_cred_handle);
     564             :     } else {
     565           0 :         if (ctx->mech_src_name != GSS_C_NO_NAME)
     566           0 :             gss_release_name(&junk, &ctx->mech_src_name);
     567             : 
     568           0 :         ret = gss_accept_sec_context(minor_status,
     569             :                                      &ctx->negotiated_ctx_id,
     570             :                                      acceptor_cred_handle,
     571             :                                      (gss_buffer_t)input_token_buffer,
     572             :                                      input_chan_bindings,
     573             :                                      &ctx->mech_src_name,
     574             :                                      &ctx->negotiated_mech_type,
     575             :                                      output_token,
     576             :                                      &ctx->mech_flags,
     577             :                                      &ctx->mech_time_rec,
     578             :                                      delegated_cred_handle);
     579           0 :         if (GSS_ERROR(ret))
     580           0 :             gss_mg_collect_error(ctx->negotiated_mech_type, ret, *minor_status);
     581           0 :         else if (ctx->negotiated_mech_type != GSS_C_NO_OID &&
     582           0 :             !gss_oid_equal(ctx->negotiated_mech_type, ctx->selected_mech_type))
     583           0 :             _gss_mg_log(1, "spnego client didn't send the mech they said they would");
     584             :     }
     585             : 
     586           0 :     return ret;
     587             : }
     588             : 
     589             : static OM_uint32 GSSAPI_CALLCONV
     590           0 : acceptor_start
     591             :            (OM_uint32 * minor_status,
     592             :             gss_ctx_id_t * context_handle,
     593             :             gss_const_cred_id_t acceptor_cred_handle,
     594             :             const gss_buffer_t input_token_buffer,
     595             :             const gss_channel_bindings_t input_chan_bindings,
     596             :             gss_name_t * src_name,
     597             :             gss_OID * mech_type,
     598             :             gss_buffer_t output_token,
     599             :             OM_uint32 * ret_flags,
     600             :             OM_uint32 * time_rec,
     601             :             gss_cred_id_t *delegated_cred_handle
     602             :            )
     603             : {
     604           0 :     OM_uint32 ret, junk;
     605           0 :     NegotiationToken nt;
     606           0 :     gss_OID_set supported_mechs = GSS_C_NO_OID_SET;
     607           0 :     size_t size;
     608           0 :     NegTokenInit *ni;
     609           0 :     gss_buffer_desc data;
     610           0 :     gss_buffer_t mech_input_token = GSS_C_NO_BUFFER;
     611           0 :     gss_buffer_desc mech_output_token;
     612           0 :     gssspnego_ctx ctx;
     613           0 :     int get_mic = 0, first_ok = 0, canonical_order;
     614           0 :     gss_const_OID advertised_mech = GSS_C_NO_OID;
     615             : 
     616           0 :     memset(&nt, 0, sizeof(nt));
     617             : 
     618           0 :     mech_output_token.value = NULL;
     619           0 :     mech_output_token.length = 0;
     620             : 
     621           0 :     if (input_token_buffer->length == 0)
     622           0 :         return send_supported_mechs (minor_status, NULL,
     623             :                                      acceptor_cred_handle, output_token);
     624             : 
     625           0 :     ret = _gss_spnego_alloc_sec_context(minor_status, context_handle);
     626           0 :     if (ret != GSS_S_COMPLETE)
     627           0 :         return ret;
     628             : 
     629           0 :     ctx = (gssspnego_ctx)*context_handle;
     630             : 
     631           0 :     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
     632             : 
     633             :     /*
     634             :      * The GSS-API encapsulation is only present on the initial
     635             :      * context token (negTokenInit).
     636             :      */
     637           0 :     ret = gss_decapsulate_token (input_token_buffer,
     638             :                                  GSS_SPNEGO_MECHANISM,
     639             :                                  &data);
     640           0 :     if (ret)
     641           0 :         goto out;
     642             : 
     643           0 :     ret = decode_NegotiationToken(data.value, data.length, &nt, &size);
     644           0 :     gss_release_buffer(minor_status, &data);
     645           0 :     if (ret) {
     646           0 :         *minor_status = ret;
     647           0 :         ret = GSS_S_DEFECTIVE_TOKEN;
     648           0 :         goto out;
     649             :     }
     650           0 :     if (nt.element != choice_NegotiationToken_negTokenInit) {
     651           0 :         *minor_status = 0;
     652           0 :         ret = GSS_S_DEFECTIVE_TOKEN;
     653           0 :         goto out;
     654             :     }
     655           0 :     ni = &nt.u.negTokenInit;
     656             : 
     657           0 :     if (ni->mechTypes.len < 1) {
     658           0 :         free_NegotiationToken(&nt);
     659           0 :         *minor_status = 0;
     660           0 :         ret = GSS_S_DEFECTIVE_TOKEN;
     661           0 :         goto out;
     662             :     }
     663             : 
     664           0 :     _gss_spnego_log_mechTypes(&ni->mechTypes);
     665             : 
     666             :     {
     667           0 :         MechTypeList mt;
     668           0 :         int kret;
     669             : 
     670           0 :         mt.len = ni->mechTypes.len;
     671           0 :         mt.val = ni->mechTypes.val;
     672             : 
     673           0 :         ASN1_MALLOC_ENCODE(MechTypeList,
     674             :                            ctx->NegTokenInit_mech_types.value,
     675             :                            ctx->NegTokenInit_mech_types.length,
     676             :                            &mt, &size, kret);
     677           0 :         if (kret) {
     678           0 :             *minor_status = kret;
     679           0 :             ret = GSS_S_FAILURE;
     680           0 :             goto out;
     681             :         }
     682             :     }
     683             : 
     684           0 :     if (acceptor_cred_handle != GSS_C_NO_CREDENTIAL)
     685           0 :         ret = _gss_spnego_inquire_cred_mechs(minor_status,
     686             :                                              acceptor_cred_handle,
     687             :                                              &supported_mechs,
     688             :                                              &canonical_order);
     689             :     else
     690           0 :         ret = _gss_spnego_indicate_mechs(minor_status, &supported_mechs);
     691           0 :     if (ret != GSS_S_COMPLETE)
     692           0 :         goto out;
     693             : 
     694             :     /*
     695             :      * First we try the opportunistic token if we have support for it,
     696             :      * don't try to verify we have credential for the token,
     697             :      * gss_accept_sec_context() will (hopefully) tell us that.
     698             :      * If that failes,
     699             :      */
     700             : 
     701           0 :     ret = select_mech(minor_status,
     702             :                       ctx,
     703             :                       acceptor_cred_handle,
     704             :                       supported_mechs,
     705             :                       &ni->mechTypes.val[0],
     706             :                       0, /* optimistic token */
     707             :                       &advertised_mech);
     708             : 
     709           0 :     if (ret == GSS_S_COMPLETE && ni->mechToken != NULL) {
     710           0 :         gss_buffer_desc ibuf;
     711             : 
     712           0 :         ibuf.length = ni->mechToken->length;
     713           0 :         ibuf.value = ni->mechToken->data;
     714           0 :         mech_input_token = &ibuf;
     715             : 
     716           0 :         _gss_spnego_log_mech("acceptor selected opportunistic mech", ctx->selected_mech_type);
     717             : 
     718           0 :         ret = mech_accept(&junk,
     719             :                           ctx,
     720             :                           acceptor_cred_handle,
     721             :                           mech_input_token,
     722             :                           input_chan_bindings,
     723             :                           &mech_output_token,
     724             :                           delegated_cred_handle);
     725           0 :         if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
     726           0 :             first_ok = 1;
     727             :         } else {
     728           0 :             ctx->selected_mech_type = GSS_C_NO_OID;
     729             :         }
     730             : 
     731           0 :         if (ret == GSS_S_COMPLETE) {
     732           0 :             ret = acceptor_complete(minor_status,
     733             :                                     ctx,
     734             :                                     &get_mic,
     735             :                                     mech_input_token,
     736             :                                     &mech_output_token,
     737             :                                     ni->mechListMIC,
     738             :                                     output_token);
     739           0 :             if (ret != GSS_S_COMPLETE)
     740           0 :                 goto out;
     741             : 
     742           0 :             ctx->flags.open = 1;
     743             :         }
     744             :     } else {
     745           0 :         *minor_status = 0;
     746           0 :         gss_release_oid_set(&junk, &supported_mechs);
     747           0 :         HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
     748           0 :         return gss_mg_set_error_string(GSS_C_NO_OID, GSS_S_NO_CONTEXT,
     749             :                                        *minor_status,
     750             :                                        "SPNEGO acceptor didn't find a prefered mechanism");
     751             :     }
     752             : 
     753             :     /*
     754             :      * If opportunistic token failed, lets try the other mechs.
     755             :      */
     756             : 
     757           0 :     if (!first_ok) {
     758             :         size_t j;
     759             : 
     760             :         /* Call glue layer to find first mech we support */
     761           0 :         for (j = 1; j < ni->mechTypes.len; ++j) {
     762           0 :             ret = select_mech(&junk,
     763             :                               ctx,
     764             :                               acceptor_cred_handle,
     765             :                               supported_mechs,
     766           0 :                               &ni->mechTypes.val[j],
     767             :                               1, /* not optimistic token */
     768             :                               &advertised_mech);
     769           0 :             if (ret == GSS_S_COMPLETE) {
     770           0 :                 _gss_spnego_log_mech("acceptor selected non-opportunistic mech",
     771           0 :                                      ctx->selected_mech_type);
     772           0 :                 break;
     773             :             }
     774             :         }
     775             :     }
     776           0 :     if (ctx->selected_mech_type == GSS_C_NO_OID) {
     777           0 :         heim_assert(ret != GSS_S_COMPLETE, "no oid and no error code?");
     778           0 :         *minor_status = junk;
     779           0 :         goto out;
     780             :     }
     781             : 
     782             :     /* The initial token always has a response */
     783           0 :     ret = send_accept(minor_status,
     784             :                       ctx,
     785             :                       first_ok,
     786             :                       &mech_output_token,
     787             :                       advertised_mech,
     788           0 :                       get_mic ? &ctx->NegTokenInit_mech_types : NULL,
     789             :                       output_token);
     790           0 :     if (ret)
     791           0 :         goto out;
     792             : 
     793           0 : out:
     794           0 :     gss_release_oid_set(&junk, &supported_mechs);
     795           0 :     if (mech_output_token.value != NULL)
     796           0 :         gss_release_buffer(&junk, &mech_output_token);
     797           0 :     free_NegotiationToken(&nt);
     798             : 
     799             : 
     800           0 :     if (ret == GSS_S_COMPLETE) {
     801           0 :         if (src_name != NULL && ctx->mech_src_name != GSS_C_NO_NAME)
     802           0 :             ret = gss_duplicate_name(minor_status,
     803           0 :                                      ctx->mech_src_name,
     804             :                                      src_name);
     805             :     }
     806             : 
     807           0 :     if (mech_type != NULL)
     808           0 :         *mech_type = ctx->negotiated_mech_type;
     809           0 :     if (ret_flags != NULL)
     810           0 :         *ret_flags = ctx->mech_flags;
     811           0 :     if (time_rec != NULL)
     812           0 :         *time_rec = ctx->mech_time_rec;
     813             : 
     814           0 :     if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
     815             :         HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
     816           0 :         return ret;
     817             :     }
     818             : 
     819           0 :     _gss_spnego_internal_delete_sec_context(&junk, context_handle,
     820             :                                             GSS_C_NO_BUFFER);
     821             : 
     822           0 :     return ret;
     823             : }
     824             : 
     825             : 
     826             : static OM_uint32 GSSAPI_CALLCONV
     827           0 : acceptor_continue
     828             :            (OM_uint32 * minor_status,
     829             :             gss_ctx_id_t * context_handle,
     830             :             gss_const_cred_id_t acceptor_cred_handle,
     831             :             const gss_buffer_t input_token_buffer,
     832             :             const gss_channel_bindings_t input_chan_bindings,
     833             :             gss_name_t * src_name,
     834             :             gss_OID * mech_type,
     835             :             gss_buffer_t output_token,
     836             :             OM_uint32 * ret_flags,
     837             :             OM_uint32 * time_rec,
     838             :             gss_cred_id_t *delegated_cred_handle
     839             :            )
     840             : {
     841           0 :     OM_uint32 ret, ret2, minor, junk;
     842           0 :     NegotiationToken nt;
     843           0 :     size_t nt_len;
     844           0 :     NegTokenResp *na;
     845           0 :     unsigned int negState = accept_incomplete;
     846           0 :     gss_buffer_t mech_input_token = GSS_C_NO_BUFFER;
     847           0 :     gss_buffer_t mech_output_token = GSS_C_NO_BUFFER;
     848           0 :     gssspnego_ctx ctx;
     849             : 
     850           0 :     ctx = (gssspnego_ctx)*context_handle;
     851             : 
     852             :     /*
     853             :      * The GSS-API encapsulation is only present on the initial
     854             :      * context token (negTokenInit).
     855             :      */
     856             : 
     857           0 :     ret = decode_NegotiationToken(input_token_buffer->value,
     858             :                                   input_token_buffer->length,
     859             :                                   &nt, &nt_len);
     860           0 :     if (ret) {
     861           0 :         *minor_status = ret;
     862           0 :         return GSS_S_DEFECTIVE_TOKEN;
     863             :     }
     864           0 :     if (nt.element != choice_NegotiationToken_negTokenResp) {
     865           0 :         *minor_status = 0;
     866           0 :         return GSS_S_DEFECTIVE_TOKEN;
     867             :     }
     868           0 :     na = &nt.u.negTokenResp;
     869             : 
     870           0 :     if (na->negState != NULL) {
     871           0 :         negState = *(na->negState);
     872             :     }
     873             : 
     874           0 :     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
     875             : 
     876             :     {
     877           0 :         gss_buffer_desc ibuf, obuf;
     878           0 :         int get_mic = 0;
     879           0 :         int require_response;
     880             : 
     881           0 :         if (na->responseToken != NULL) {
     882           0 :             ibuf.length = na->responseToken->length;
     883           0 :             ibuf.value = na->responseToken->data;
     884           0 :             mech_input_token = &ibuf;
     885             :         } else {
     886           0 :             ibuf.value = NULL;
     887           0 :             ibuf.length = 0;
     888             :         }
     889             : 
     890           0 :         if (mech_input_token != GSS_C_NO_BUFFER) {
     891             : 
     892           0 :             ret = mech_accept(minor_status,
     893             :                               ctx,
     894             :                               acceptor_cred_handle,
     895             :                               mech_input_token,
     896             :                               input_chan_bindings,
     897             :                               &obuf,
     898             :                               delegated_cred_handle);
     899           0 :             mech_output_token = &obuf;
     900           0 :             if (ret != GSS_S_COMPLETE && ret != GSS_S_CONTINUE_NEEDED) {
     901           0 :                 free_NegotiationToken(&nt);
     902           0 :                 send_reject(&junk, mech_output_token, output_token);
     903           0 :                 gss_release_buffer(&junk, mech_output_token);
     904           0 :                 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
     905           0 :                 return ret;
     906             :             }
     907           0 :             if (ret == GSS_S_COMPLETE)
     908           0 :                 ctx->flags.open = 1;
     909             :         } else
     910           0 :             ret = GSS_S_COMPLETE;
     911             : 
     912           0 :         if (ret == GSS_S_COMPLETE)
     913           0 :             ret = acceptor_complete(minor_status,
     914             :                                     ctx,
     915             :                                     &get_mic,
     916             :                                     mech_input_token,
     917             :                                     mech_output_token,
     918             :                                     na->mechListMIC,
     919             :                                     output_token);
     920             : 
     921           0 :         if (ctx->mech_flags & GSS_C_DCE_STYLE)
     922           0 :             require_response = (negState != accept_completed);
     923             :         else
     924           0 :             require_response = 0;
     925             : 
     926             :         /*
     927             :          * Check whether we need to send a result: there should be only
     928             :          * one accept_completed response sent in the entire negotiation
     929             :          */
     930           0 :         if ((mech_output_token != GSS_C_NO_BUFFER &&
     931           0 :              mech_output_token->length != 0)
     932           0 :             || (ctx->flags.open && negState == accept_incomplete)
     933           0 :             || require_response
     934           0 :             || get_mic) {
     935           0 :             ret2 = send_accept (minor_status,
     936             :                                 ctx,
     937             :                                 0, /* ignored on subsequent tokens */
     938             :                                 mech_output_token,
     939             :                                 GSS_C_NO_OID,
     940           0 :                                 get_mic ? &ctx->NegTokenInit_mech_types : NULL,
     941             :                                 output_token);
     942           0 :             if (ret2)
     943           0 :                 goto out;
     944             :         } else
     945           0 :             ret2 = GSS_S_COMPLETE;
     946             : 
     947           0 :      out:
     948           0 :         if (ret2 != GSS_S_COMPLETE)
     949           0 :             ret = ret2;
     950           0 :         if (mech_output_token != NULL)
     951           0 :             gss_release_buffer(&minor, mech_output_token);
     952           0 :         free_NegotiationToken(&nt);
     953             :     }
     954             : 
     955           0 :     if (ret == GSS_S_COMPLETE) {
     956           0 :         if (src_name != NULL && ctx->mech_src_name != GSS_C_NO_NAME)
     957           0 :             ret = gss_duplicate_name(minor_status,
     958           0 :                                      ctx->mech_src_name,
     959             :                                      src_name);
     960             :     }
     961             : 
     962           0 :     if (mech_type != NULL)
     963           0 :         *mech_type = ctx->negotiated_mech_type;
     964           0 :     if (ret_flags != NULL)
     965           0 :         *ret_flags = ctx->mech_flags;
     966           0 :     if (time_rec != NULL)
     967           0 :         *time_rec = ctx->mech_time_rec;
     968             : 
     969           0 :     if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
     970             :         HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
     971           0 :         return ret;
     972             :     }
     973             : 
     974           0 :     _gss_spnego_internal_delete_sec_context(&minor, context_handle,
     975             :                                    GSS_C_NO_BUFFER);
     976             : 
     977           0 :     return ret;
     978             : }
     979             : 
     980             : OM_uint32 GSSAPI_CALLCONV
     981           0 : _gss_spnego_accept_sec_context
     982             :            (OM_uint32 * minor_status,
     983             :             gss_ctx_id_t * context_handle,
     984             :             gss_const_cred_id_t acceptor_cred_handle,
     985             :             const gss_buffer_t input_token_buffer,
     986             :             const gss_channel_bindings_t input_chan_bindings,
     987             :             gss_name_t * src_name,
     988             :             gss_OID * mech_type,
     989             :             gss_buffer_t output_token,
     990             :             OM_uint32 * ret_flags,
     991             :             OM_uint32 * time_rec,
     992             :             gss_cred_id_t *delegated_cred_handle
     993             :            )
     994             : {
     995           0 :     _gss_accept_sec_context_t *func;
     996             : 
     997           0 :     *minor_status = 0;
     998             : 
     999           0 :     output_token->length = 0;
    1000           0 :     output_token->value  = NULL;
    1001             : 
    1002           0 :     if (src_name != NULL)
    1003           0 :         *src_name = GSS_C_NO_NAME;
    1004           0 :     if (mech_type != NULL)
    1005           0 :         *mech_type = GSS_C_NO_OID;
    1006           0 :     if (ret_flags != NULL)
    1007           0 :         *ret_flags = 0;
    1008           0 :     if (time_rec != NULL)
    1009           0 :         *time_rec = 0;
    1010           0 :     if (delegated_cred_handle != NULL)
    1011           0 :         *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
    1012             : 
    1013             : 
    1014           0 :     if (*context_handle == GSS_C_NO_CONTEXT)
    1015           0 :         func = acceptor_start;
    1016             :     else
    1017           0 :         func = acceptor_continue;
    1018             : 
    1019             : 
    1020           0 :     return (*func)(minor_status, context_handle, acceptor_cred_handle,
    1021             :                    input_token_buffer, input_chan_bindings,
    1022             :                    src_name, mech_type, output_token, ret_flags,
    1023             :                    time_rec, delegated_cred_handle);
    1024             : }

Generated by: LCOV version 1.14