LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/gssapi/spnego - init_sec_context.c (source / functions) Hit Total Coverage
Test: coverage report for master 469b22b8 Lines: 0 383 0.0 %
Date: 2024-06-10 12:05:21 Functions: 0 7 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 1997 - 2004 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             : #define GSISC(name) \
      37             : static                                                             \
      38             : OM_uint32 name(OM_uint32 *, gss_const_cred_id_t, gssspnego_ctx,    \
      39             :                gss_const_name_t, gss_const_OID,                    \
      40             :                OM_uint32, OM_uint32, const gss_channel_bindings_t, \
      41             :                gss_const_buffer_t, gss_buffer_t,                   \
      42             :                OM_uint32 *, OM_uint32 *)
      43             : 
      44             : GSISC(spnego_initial);
      45             : GSISC(spnego_reply);
      46             : GSISC(wait_server_mic);
      47             : GSISC(step_completed);
      48             : 
      49             : 
      50             :  /*
      51             :   * Is target_name an sane target for `mech´.
      52             :   */
      53             : 
      54             : static OM_uint32
      55           0 : initiator_approved(OM_uint32 *minor_status,
      56             :                    void *userptr,
      57             :                    gss_const_name_t target_name,
      58             :                    gss_const_cred_id_t cred,
      59             :                    gss_OID mech)
      60             : {
      61           0 :     OM_uint32 min_stat, maj_stat;
      62           0 :     gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
      63           0 :     gss_buffer_desc out;
      64           0 :     struct gssspnego_optimistic_ctx *sel = userptr;
      65           0 :     gss_OID negotiated_mech_type = GSS_C_NO_OID;
      66           0 :     OM_uint32 flags = 0, time_rec = 0;
      67           0 :     auth_scheme scheme;
      68           0 :     int negoex = 0;
      69             : 
      70           0 :     maj_stat = gss_init_sec_context(&min_stat,
      71             :                                     cred,
      72             :                                     &ctx,
      73           0 :                                     sel->target_name,
      74             :                                     mech,
      75             :                                     sel->req_flags,
      76             :                                     sel->time_req,
      77             :                                     sel->input_chan_bindings,
      78             :                                     GSS_C_NO_BUFFER,
      79             :                                     &negotiated_mech_type,
      80             :                                     &out,
      81             :                                     &flags,
      82             :                                     &time_rec);
      83           0 :     if (GSS_ERROR(maj_stat)) {
      84           0 :         gss_mg_collect_error(mech, maj_stat, min_stat);
      85           0 :         *minor_status = min_stat;
      86           0 :         return maj_stat;
      87             :     }
      88             : 
      89           0 :     if (gssspi_query_mechanism_info(&min_stat, mech, scheme) == GSS_S_COMPLETE)
      90           0 :         negoex = 1;
      91             : 
      92           0 :     if (sel->preferred_mech_type == GSS_C_NO_OID) {
      93           0 :         sel->preferred_mech_type = mech;
      94           0 :         sel->negotiated_mech_type = negotiated_mech_type;
      95           0 :         sel->optimistic_token = out;
      96           0 :         sel->optimistic_flags = flags;
      97           0 :         sel->optimistic_time_rec = time_rec;
      98           0 :         sel->gssctx = ctx;
      99           0 :         if (maj_stat == GSS_S_COMPLETE)
     100           0 :             sel->complete = 1;
     101           0 :         if (negoex)
     102           0 :             memcpy(sel->scheme, scheme, GUID_LENGTH);
     103             :     } else {
     104           0 :         gss_release_buffer(&min_stat, &out);
     105           0 :         gss_delete_sec_context(&min_stat, &ctx, NULL);
     106             :     }
     107             : 
     108           0 :     maj_stat = GSS_S_COMPLETE;
     109             : 
     110           0 :     if (negoex) {
     111           0 :         maj_stat = _gss_negoex_add_auth_mech(minor_status, sel->spnegoctx,
     112             :                                              mech, scheme);
     113             :     }
     114             : 
     115           0 :     return maj_stat;
     116             : }
     117             : 
     118             : /*
     119             :  * Send a reply. Note that we only need to send a reply if we
     120             :  * need to send a MIC or a mechanism token. Otherwise, we can
     121             :  * return an empty buffer.
     122             :  *
     123             :  * The return value of this will be returned to the API, so it
     124             :  * must return GSS_S_CONTINUE_NEEDED if a token was generated.
     125             :  */
     126             : static OM_uint32
     127           0 : make_reply(OM_uint32 *minor_status,
     128             :            gssspnego_ctx ctx,
     129             :            gss_buffer_t mech_token,
     130             :            gss_buffer_t output_token)
     131             : {
     132           0 :     NegotiationToken nt;
     133           0 :     gss_buffer_desc mic_buf;
     134           0 :     OM_uint32 ret, minor;
     135           0 :     size_t size;
     136           0 :     NegStateEnum state;
     137             : 
     138           0 :     memset(&nt, 0, sizeof(nt));
     139             : 
     140           0 :     nt.element = choice_NegotiationToken_negTokenResp;
     141             : 
     142           0 :     nt.u.negTokenResp.negState = NULL;
     143           0 :     nt.u.negTokenResp.supportedMech = NULL;
     144             : 
     145           0 :     output_token->length = 0;
     146           0 :     output_token->value = NULL;
     147             : 
     148             :     /* figure out our status */
     149             : 
     150           0 :     if (ctx->flags.open) {
     151           0 :         if (ctx->flags.verified_mic == 1 || ctx->flags.require_mic == 0)
     152           0 :             state = accept_completed;
     153             :         else
     154           0 :             state = accept_incomplete;
     155             :     } else  {
     156           0 :         state = accept_incomplete;
     157             :     }
     158             : 
     159           0 :     if (mech_token->length == 0) {
     160           0 :         nt.u.negTokenResp.responseToken = NULL;
     161             :     } else {
     162           0 :         ALLOC(nt.u.negTokenResp.responseToken, 1);
     163           0 :         if (nt.u.negTokenResp.responseToken == NULL) {
     164           0 :             free_NegotiationToken(&nt);
     165           0 :             *minor_status = ENOMEM;
     166           0 :             return GSS_S_FAILURE;
     167             :         }
     168           0 :         nt.u.negTokenResp.responseToken->length = mech_token->length;
     169           0 :         nt.u.negTokenResp.responseToken->data   = mech_token->value;
     170           0 :         mech_token->length = 0;
     171           0 :         mech_token->value  = NULL;
     172             :     }
     173             : 
     174             :     /*
     175             :      * XXX should limit when we send the MIC ?
     176             :      */
     177           0 :     if (ctx->flags.open && ctx->flags.sent_mic == 0) {
     178             : 
     179           0 :         ctx->flags.sent_mic = 1;
     180             : 
     181           0 :         ret = gss_get_mic(minor_status,
     182           0 :                           ctx->negotiated_ctx_id,
     183             :                           0,
     184           0 :                           &ctx->NegTokenInit_mech_types,
     185             :                           &mic_buf);
     186           0 :         if (ret == GSS_S_COMPLETE) {
     187           0 :             _gss_spnego_ntlm_reset_crypto(&minor, ctx, FALSE);
     188             : 
     189           0 :             ALLOC(nt.u.negTokenResp.mechListMIC, 1);
     190           0 :             if (nt.u.negTokenResp.mechListMIC == NULL) {
     191           0 :                 gss_release_buffer(minor_status, &mic_buf);
     192           0 :                 free_NegotiationToken(&nt);
     193           0 :                 *minor_status = ENOMEM;
     194           0 :                 return GSS_S_FAILURE;
     195             :             }
     196             : 
     197           0 :             nt.u.negTokenResp.mechListMIC->length = mic_buf.length;
     198           0 :             nt.u.negTokenResp.mechListMIC->data   = mic_buf.value;
     199             :             /* mic_buf free()d with nt */
     200           0 :         } else if (ret == GSS_S_UNAVAILABLE) {
     201             :             /* lets hope that its ok to not send te mechListMIC for broken mechs */
     202           0 :             nt.u.negTokenResp.mechListMIC = NULL;
     203           0 :             ctx->flags.require_mic = 0;
     204             :         } else {
     205           0 :             free_NegotiationToken(&nt);
     206           0 :             *minor_status = ENOMEM;
     207           0 :             return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM,
     208             :                                            ret, *minor_status,
     209             :                                            "SPNEGO failed to sign MIC");
     210             :         }
     211             :     } else {
     212           0 :         nt.u.negTokenResp.mechListMIC = NULL;
     213             :     }
     214             : 
     215           0 :     ALLOC(nt.u.negTokenResp.negState, 1);
     216           0 :     if (nt.u.negTokenResp.negState == NULL) {
     217           0 :         free_NegotiationToken(&nt);
     218           0 :         *minor_status = ENOMEM;
     219           0 :         return GSS_S_FAILURE;
     220             :     }
     221           0 :     *nt.u.negTokenResp.negState = state;
     222             : 
     223           0 :     ASN1_MALLOC_ENCODE(NegotiationToken,
     224             :                        output_token->value, output_token->length,
     225             :                        &nt, &size, ret);
     226           0 :     free_NegotiationToken(&nt);
     227           0 :     if (ret) {
     228           0 :         *minor_status = ret;
     229           0 :         return GSS_S_FAILURE;
     230             :     }
     231             : 
     232           0 :     if (state != accept_completed)
     233           0 :         return GSS_S_CONTINUE_NEEDED;
     234             : 
     235           0 :     return GSS_S_COMPLETE;
     236             : }
     237             : 
     238             : static OM_uint32
     239           0 : spnego_initial(OM_uint32 * minor_status,
     240             :                gss_const_cred_id_t cred,
     241             :                gssspnego_ctx ctx,
     242             :                gss_const_name_t target_name,
     243             :                gss_const_OID mech_type,
     244             :                OM_uint32 req_flags,
     245             :                OM_uint32 time_req,
     246             :                const gss_channel_bindings_t input_chan_bindings,
     247             :                gss_const_buffer_t input_token,
     248             :                gss_buffer_t output_token,
     249             :                OM_uint32 * ret_flags,
     250             :                OM_uint32 * time_rec)
     251             : {
     252           0 :     NegotiationToken nt;
     253           0 :     int ret;
     254           0 :     OM_uint32 sub, minor;
     255           0 :     gss_buffer_desc mech_token;
     256           0 :     size_t size = 0;
     257           0 :     gss_buffer_desc data;
     258           0 :     struct gssspnego_optimistic_ctx sel;
     259             : 
     260           0 :     *minor_status = 0;
     261             : 
     262           0 :     memset(&nt, 0, sizeof(nt));
     263             : 
     264           0 :     if (target_name == GSS_C_NO_NAME)
     265           0 :         return GSS_S_BAD_NAME;
     266             : 
     267           0 :     sub = gss_duplicate_name(&minor, target_name, &ctx->target_name);
     268           0 :     if (GSS_ERROR(sub)) {
     269           0 :         *minor_status = minor;
     270           0 :         return sub;
     271             :     }
     272             : 
     273           0 :     nt.element = choice_NegotiationToken_negTokenInit;
     274             : 
     275           0 :     ctx->flags.local = 1;
     276             : 
     277           0 :     memset(&sel, 0, sizeof(sel));
     278             : 
     279           0 :     sel.spnegoctx = ctx;
     280           0 :     sel.target_name = ctx->target_name;
     281           0 :     sel.preferred_mech_type = GSS_C_NO_OID;
     282           0 :     sel.req_flags = req_flags;
     283           0 :     sel.time_req = time_req;
     284           0 :     sel.input_chan_bindings = (gss_channel_bindings_t)input_chan_bindings;
     285             : 
     286           0 :     sub = _gss_spnego_indicate_mechtypelist(&minor,
     287           0 :                                             ctx->target_name,
     288             :                                             req_flags,
     289             :                                             initiator_approved,
     290             :                                             &sel,
     291             :                                             0,
     292             :                                             cred,
     293             :                                             &nt.u.negTokenInit.mechTypes,
     294             :                                             &ctx->preferred_mech_type);
     295           0 :     if (GSS_ERROR(sub)) {
     296           0 :         *minor_status = minor;
     297           0 :         return sub;
     298             :     }
     299             : 
     300           0 :     _gss_spnego_log_mechTypes(&nt.u.negTokenInit.mechTypes);
     301             : 
     302           0 :     nt.u.negTokenInit.reqFlags = NULL;
     303             : 
     304           0 :     if (gss_oid_equal(ctx->preferred_mech_type, GSS_NEGOEX_MECHANISM)) {
     305           0 :         struct negoex_auth_mech *mech;
     306             : 
     307           0 :         sub = _gss_negoex_init(&minor,
     308             :                                &sel,
     309             :                                ctx,
     310             :                                (gss_cred_id_t)cred,
     311             :                                req_flags,
     312             :                                time_req,
     313             :                                input_chan_bindings,
     314             :                                GSS_C_NO_BUFFER,
     315             :                                &mech_token);
     316           0 :         if (GSS_ERROR(sub)) {
     317           0 :             free_NegotiationToken(&nt);
     318           0 :             return gss_mg_set_error_string(GSS_C_NO_OID, sub, minor,
     319             :                                            "NegoEx could not generate a context token");
     320             :         }
     321           0 :         mech = _gss_negoex_negotiated_mech(ctx);
     322           0 :         ctx->flags.maybe_open = mech && mech->complete;
     323           0 :         gss_release_buffer(&minor, &sel.optimistic_token);
     324             :     } else {
     325             :         /* optimistic token from selection context */
     326           0 :         mech_token = sel.optimistic_token;
     327           0 :         ctx->mech_flags = sel.optimistic_flags;
     328           0 :         ctx->mech_time_rec = sel.optimistic_time_rec;
     329           0 :         ctx->negotiated_mech_type = sel.negotiated_mech_type;
     330           0 :         ctx->negotiated_ctx_id = sel.gssctx;
     331           0 :         ctx->flags.maybe_open = sel.complete;
     332             :     }
     333             : 
     334           0 :     if (ctx->preferred_mech_type == GSS_C_NO_OID) {
     335           0 :         free_NegotiationToken(&nt);
     336           0 :         *minor_status = 0;
     337           0 :         return gss_mg_set_error_string(GSS_C_NO_OID, GSS_S_NO_CONTEXT, 0,
     338             :                                        "SPNEGO could not find a preferred mechanism");
     339             :     }
     340             : 
     341             : 
     342           0 :     if (mech_token.length != 0) {
     343           0 :         ALLOC(nt.u.negTokenInit.mechToken, 1);
     344           0 :         if (nt.u.negTokenInit.mechToken == NULL) {
     345           0 :             free_NegotiationToken(&nt);
     346           0 :             gss_release_buffer(&minor, &mech_token);
     347           0 :             *minor_status = ENOMEM;
     348           0 :             return GSS_S_FAILURE;
     349             :         }
     350           0 :         nt.u.negTokenInit.mechToken->length = mech_token.length;
     351           0 :         nt.u.negTokenInit.mechToken->data = malloc(mech_token.length);
     352           0 :         if (nt.u.negTokenInit.mechToken->data == NULL && mech_token.length != 0) {
     353           0 :             free_NegotiationToken(&nt);
     354           0 :             gss_release_buffer(&minor, &mech_token);
     355           0 :             *minor_status = ENOMEM;
     356           0 :             return GSS_S_FAILURE;
     357             :         }
     358           0 :         memcpy(nt.u.negTokenInit.mechToken->data, mech_token.value, mech_token.length);
     359           0 :         gss_release_buffer(&minor, &mech_token);
     360             :     } else
     361           0 :         nt.u.negTokenInit.mechToken = NULL;
     362             : 
     363           0 :     nt.u.negTokenInit.mechListMIC = NULL;
     364             : 
     365             :     {
     366           0 :         MechTypeList mt;
     367             : 
     368           0 :         mt.len = nt.u.negTokenInit.mechTypes.len;
     369           0 :         mt.val = nt.u.negTokenInit.mechTypes.val;
     370             : 
     371           0 :         ASN1_MALLOC_ENCODE(MechTypeList,
     372             :                            ctx->NegTokenInit_mech_types.value,
     373             :                            ctx->NegTokenInit_mech_types.length,
     374             :                            &mt, &size, ret);
     375           0 :         if (ret) {
     376           0 :             *minor_status = ret;
     377           0 :             free_NegotiationToken(&nt);
     378           0 :             return GSS_S_FAILURE;
     379             :         }
     380             :     }
     381             : 
     382           0 :     ASN1_MALLOC_ENCODE(NegotiationToken, data.value, data.length, &nt, &size, ret);
     383           0 :     free_NegotiationToken(&nt);
     384           0 :     if (ret) {
     385           0 :         return GSS_S_FAILURE;
     386             :     }
     387           0 :     if (data.length != size)
     388           0 :         abort();
     389             : 
     390           0 :     sub = gss_encapsulate_token(&data,
     391             :                                 GSS_SPNEGO_MECHANISM,
     392             :                                 output_token);
     393           0 :     free (data.value);
     394             : 
     395           0 :     if (sub) {
     396           0 :         return sub;
     397             :     }
     398             : 
     399           0 :     if (ret_flags)
     400           0 :         *ret_flags = ctx->mech_flags;
     401           0 :     if (time_rec)
     402           0 :         *time_rec = ctx->mech_time_rec;
     403             : 
     404           0 :     ctx->initiator_state = spnego_reply;
     405             : 
     406           0 :     return GSS_S_CONTINUE_NEEDED;
     407             : }
     408             : 
     409             : /*
     410             :  *
     411             :  */
     412             : 
     413             : static OM_uint32
     414           0 : spnego_reply(OM_uint32 * minor_status,
     415             :              gss_const_cred_id_t cred,
     416             :              gssspnego_ctx ctx,
     417             :              gss_const_name_t target_name,
     418             :              gss_const_OID mech_type,
     419             :              OM_uint32 req_flags,
     420             :              OM_uint32 time_req,
     421             :              const gss_channel_bindings_t input_chan_bindings,
     422             :              gss_const_buffer_t input_token,
     423             :              gss_buffer_t output_token,
     424             :              OM_uint32 * ret_flags,
     425             :              OM_uint32 * time_rec)
     426             : {
     427           0 :     OM_uint32 ret, minor;
     428           0 :     NegotiationToken resp;
     429           0 :     gss_buffer_desc mech_output_token;
     430           0 :     NegStateEnum negState;
     431             : 
     432           0 :     *minor_status = 0;
     433             : 
     434           0 :     output_token->length = 0;
     435           0 :     output_token->value  = NULL;
     436             : 
     437           0 :     mech_output_token.length = 0;
     438           0 :     mech_output_token.value = NULL;
     439             : 
     440           0 :     ret = decode_NegotiationToken(input_token->value, input_token->length,
     441             :                                   &resp, NULL);
     442           0 :     if (ret)
     443           0 :       return ret;
     444             : 
     445             :     /* The SPNEGO token must be a negTokenResp */
     446           0 :     if (resp.element != choice_NegotiationToken_negTokenResp) {
     447           0 :         free_NegotiationToken(&resp);
     448           0 :         *minor_status = 0;
     449           0 :         return GSS_S_BAD_MECH;
     450             :     }
     451             : 
     452             :     /*
     453             :      * When negState is absent, the actual state should be inferred from
     454             :      * the state of the negotiated mechanism context. (RFC 4178 4.2.2.)
     455             :      */
     456           0 :     if (resp.u.negTokenResp.negState != NULL)
     457           0 :         negState = *resp.u.negTokenResp.negState;
     458             :     else
     459           0 :         negState = accept_incomplete;
     460             : 
     461             :     /*
     462             :      * Pick up the mechanism that the acceptor selected, only pick up
     463             :      * the first selection.
     464             :      */
     465             : 
     466           0 :     if (ctx->selected_mech_type == GSS_C_NO_OID && resp.u.negTokenResp.supportedMech) {
     467           0 :         gss_OID_desc oid;
     468           0 :         size_t len;
     469             : 
     470           0 :         ctx->flags.seen_supported_mech = 1;
     471             : 
     472           0 :         oid.length = (OM_uint32)der_length_oid(resp.u.negTokenResp.supportedMech);
     473           0 :         oid.elements = malloc(oid.length);
     474           0 :         if (oid.elements == NULL) {
     475           0 :             free_NegotiationToken(&resp);
     476           0 :             return GSS_S_BAD_MECH;
     477             :         }
     478           0 :         ret = der_put_oid(((uint8_t *)oid.elements) + oid.length - 1,
     479           0 :                           oid.length,
     480           0 :                           resp.u.negTokenResp.supportedMech,
     481             :                           &len);
     482           0 :         if (ret || len != oid.length) {
     483           0 :             free(oid.elements);
     484           0 :             free_NegotiationToken(&resp);
     485           0 :             return GSS_S_BAD_MECH;
     486             :         }
     487             : 
     488           0 :         if (gss_oid_equal(GSS_SPNEGO_MECHANISM, &oid)) {
     489           0 :             free(oid.elements);
     490           0 :             free_NegotiationToken(&resp);
     491           0 :             return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM,
     492           0 :                                            GSS_S_BAD_MECH, (*minor_status = EINVAL),
     493             :                                            "SPNEGO acceptor picked SPNEGO??");
     494             :         }
     495             : 
     496             :         /* check if the acceptor took our optimistic token */
     497           0 :         if (gss_oid_equal(ctx->preferred_mech_type, &oid)) {
     498           0 :             ctx->selected_mech_type = ctx->preferred_mech_type;
     499           0 :         } else if (gss_oid_equal(ctx->preferred_mech_type, GSS_KRB5_MECHANISM) &&
     500           0 :                    gss_oid_equal(&oid, &_gss_spnego_mskrb_mechanism_oid_desc)) {
     501             :             /* mis-encoded asn1 type from msft servers */
     502           0 :             ctx->selected_mech_type = ctx->preferred_mech_type;
     503             :         } else {
     504             :             /* nope, lets start over */
     505           0 :             gss_delete_sec_context(&minor, &ctx->negotiated_ctx_id,
     506             :                                    GSS_C_NO_BUFFER);
     507           0 :             ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;
     508             : 
     509           0 :             if (gss_oid_equal(&oid, GSS_NEGOEX_MECHANISM))
     510           0 :                 ctx->selected_mech_type = GSS_NEGOEX_MECHANISM;
     511             :             else
     512           0 :                 ctx->selected_mech_type = _gss_mg_support_mechanism(&oid);
     513             : 
     514             :             /* XXX check that server pick a mechanism we proposed */
     515           0 :             if (ctx->selected_mech_type == GSS_C_NO_OID) {
     516           0 :                 free(oid.elements);
     517           0 :                 free_NegotiationToken(&resp);
     518           0 :                 return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM,
     519           0 :                                                GSS_S_BAD_MECH, (*minor_status = EINVAL),
     520             :                                                "SPNEGO acceptor sent unsupported supportedMech");
     521             :             }
     522             :         }
     523             : 
     524           0 :         _gss_spnego_log_mech("initiator selected mechanism", ctx->selected_mech_type);
     525             : 
     526           0 :         free(oid.elements);
     527             : 
     528           0 :     } else if (ctx->selected_mech_type == NULL) {
     529           0 :         free_NegotiationToken(&resp);
     530           0 :         return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM,
     531           0 :                                        GSS_S_BAD_MECH, (*minor_status = EINVAL),
     532             :                                        "SPNEGO acceptor didn't send supportedMech");
     533             :     }
     534             : 
     535             :     /* if a token (of non zero length) pass to underlaying mech */
     536           0 :     if ((resp.u.negTokenResp.responseToken != NULL && resp.u.negTokenResp.responseToken->length) ||
     537           0 :         ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
     538           0 :         gss_buffer_desc mech_input_token;
     539             : 
     540           0 :         if (resp.u.negTokenResp.responseToken) {
     541           0 :             mech_input_token.length = resp.u.negTokenResp.responseToken->length;
     542           0 :             mech_input_token.value  = resp.u.negTokenResp.responseToken->data;
     543             :         } else {
     544           0 :             mech_input_token.length = 0;
     545           0 :             mech_input_token.value = NULL;
     546             :         }
     547             : 
     548             :         /* Fall through as if the negotiated mechanism
     549             :            was requested explicitly */
     550           0 :         if (gss_oid_equal(ctx->selected_mech_type, GSS_NEGOEX_MECHANISM)) {
     551           0 :             ret = _gss_negoex_init(&minor,
     552             :                                    NULL, /* no optimistic token */
     553             :                                    ctx,
     554             :                                    (gss_cred_id_t)cred,
     555             :                                    req_flags,
     556             :                                    time_req,
     557             :                                    input_chan_bindings,
     558             :                                    &mech_input_token,
     559             :                                    &mech_output_token);
     560             :         } else {
     561           0 :             ret = gss_init_sec_context(&minor,
     562             :                                        cred,
     563             :                                        &ctx->negotiated_ctx_id,
     564           0 :                                        ctx->target_name,
     565             :                                        ctx->selected_mech_type,
     566             :                                        req_flags,
     567             :                                        time_req,
     568             :                                        input_chan_bindings,
     569             :                                        &mech_input_token,
     570             :                                        &ctx->negotiated_mech_type,
     571             :                                        &mech_output_token,
     572             :                                        &ctx->mech_flags,
     573             :                                        &ctx->mech_time_rec);
     574           0 :             if (GSS_ERROR(ret)) {
     575           0 :                 gss_mg_collect_error(ctx->selected_mech_type, ret, minor);
     576             :             }
     577             :         }
     578             :         /*
     579             :          * If the acceptor rejected, we're out even if the inner context is
     580             :          * now complete. Note that the rejection is not integrity-protected.
     581             :          */
     582           0 :         if (negState == reject)
     583           0 :             ret = GSS_S_BAD_MECH;
     584           0 :         if (GSS_ERROR(ret)) {
     585           0 :             free_NegotiationToken(&resp);
     586           0 :             *minor_status = minor;
     587           0 :             return ret;
     588             :         }
     589           0 :         if (ret == GSS_S_COMPLETE) {
     590           0 :             ctx->flags.open = 1;
     591             :         }
     592           0 :     } else if (negState == reject) {
     593           0 :         free_NegotiationToken(&resp);
     594           0 :         return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM,
     595           0 :                                        GSS_S_BAD_MECH, (*minor_status = EPERM),
     596             :                                        "SPNEGO acceptor rejected initiator token");
     597           0 :     } else if (negState == accept_completed) {
     598             :         /*
     599             :          * Note that the accept_completed isn't integrity-protected, but
     600             :          * ctx->maybe_open can only be true if the inner context is fully
     601             :          * established.
     602             :          */
     603           0 :         if (ctx->flags.maybe_open)
     604           0 :             ctx->flags.open = 1;
     605             : 
     606           0 :         if (!ctx->flags.open) {
     607           0 :             free_NegotiationToken(&resp);
     608           0 :             return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM,
     609           0 :                                            GSS_S_BAD_MECH, (*minor_status = EINVAL),
     610             :                                            "SPNEGO acceptor sent acceptor complete, "
     611             :                                            "but we are not complete yet");
     612             :         }
     613             :     }
     614             : 
     615           0 :     if (negState == request_mic) {
     616           0 :         ctx->flags.peer_require_mic = 1;
     617             :     }
     618             : 
     619           0 :     if (ctx->flags.open && ctx->flags.verified_mic == 0) {
     620             : 
     621           0 :         ctx->flags.require_mic = 1; /* default is to require a MIC */
     622           0 :         ctx->flags.safe_omit = _gss_spnego_safe_omit_mechlist_mic(ctx);
     623             :         
     624             :         /*
     625             :          * If the peer sent mechListMIC, require it to verify ...
     626             :          */
     627           0 :         if (resp.u.negTokenResp.mechListMIC) {
     628           0 :             heim_octet_string *m = resp.u.negTokenResp.mechListMIC;
     629             : 
     630             :             /* ...unless its a windows 2000 server that sends the
     631             :              * responseToken inside the mechListMIC too. We only
     632             :              * accept this condition if would have been safe to omit
     633             :              * anyway. */
     634             : 
     635           0 :             if (ctx->flags.safe_omit
     636           0 :                 && resp.u.negTokenResp.responseToken
     637           0 :                 && der_heim_octet_string_cmp(m, resp.u.negTokenResp.responseToken) == 0)
     638             :             {
     639           0 :                 ctx->flags.require_mic = 0;
     640             :             }
     641             :         }
     642             : 
     643             :     } else {
     644           0 :         ctx->flags.require_mic = 0;
     645             :     }
     646             : 
     647             :     /*
     648             :      * If we are supposed to check mic and have it, force checking now.
     649             :      */
     650             : 
     651           0 :     if (ctx->flags.require_mic && resp.u.negTokenResp.mechListMIC) {
     652             : 
     653           0 :         ret = _gss_spnego_verify_mechtypes_mic(minor_status, ctx,
     654             :                                                resp.u.negTokenResp.mechListMIC);
     655           0 :         if (ret) {
     656           0 :             free_NegotiationToken(&resp);
     657           0 :             return ret;
     658             :         }
     659             :     }
     660             : 
     661             :     /*
     662             :      * Now that underlaying mech is open (conncted), we can figure out
     663             :      * what nexd step to go to.
     664             :      */
     665             : 
     666           0 :     if (ctx->flags.open) {
     667             : 
     668           0 :         if (negState == accept_completed && ctx->flags.safe_omit) {
     669           0 :             ctx->initiator_state = step_completed;
     670           0 :             ret = GSS_S_COMPLETE;
     671           0 :         } else if (ctx->flags.require_mic != 0 && ctx->flags.verified_mic == 0) {
     672           0 :             ctx->initiator_state = wait_server_mic;
     673           0 :             ret = GSS_S_CONTINUE_NEEDED;
     674             :         } else {
     675           0 :             ctx->initiator_state = step_completed;
     676           0 :             ret = GSS_S_COMPLETE;
     677             :         }
     678             :     }
     679             : 
     680           0 :     if (negState != accept_completed ||
     681           0 :         ctx->initiator_state != step_completed ||
     682           0 :         mech_output_token.length)
     683             :     {
     684           0 :         OM_uint32 ret2;
     685           0 :         ret2 = make_reply(minor_status, ctx,
     686             :                           &mech_output_token,
     687             :                           output_token);
     688           0 :         if (ret2)
     689           0 :             ret = ret2;
     690             :     }
     691             : 
     692           0 :     free_NegotiationToken(&resp);
     693             : 
     694           0 :     gss_release_buffer(&minor, &mech_output_token);
     695             : 
     696           0 :     if (ret_flags)
     697           0 :         *ret_flags = ctx->mech_flags;
     698           0 :     if (time_rec)
     699           0 :         *time_rec = ctx->mech_time_rec;
     700             : 
     701           0 :     return ret;
     702             : }
     703             : 
     704             : static OM_uint32
     705           0 : wait_server_mic(OM_uint32 * minor_status,
     706             :                 gss_const_cred_id_t cred,
     707             :                 gssspnego_ctx ctx,
     708             :                 gss_const_name_t target_name,
     709             :                 gss_const_OID mech_type,
     710             :                 OM_uint32 req_flags,
     711             :                 OM_uint32 time_req,
     712             :                 const gss_channel_bindings_t input_chan_bindings,
     713             :                 gss_const_buffer_t input_token,
     714             :                 gss_buffer_t output_token,
     715             :                 OM_uint32 * ret_flags,
     716             :                 OM_uint32 * time_rec)
     717             : {
     718           0 :     OM_uint32 major_status;
     719           0 :     NegotiationToken resp;
     720           0 :     int ret;
     721             : 
     722           0 :     ret = decode_NegotiationToken(input_token->value, input_token->length, &resp, NULL);
     723           0 :     if (ret)
     724           0 :         return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM,
     725             :                                        GSS_S_BAD_MECH, ret,
     726             :                                        "Failed to decode NegotiationToken");
     727             : 
     728           0 :     if (resp.element != choice_NegotiationToken_negTokenResp
     729           0 :         || resp.u.negTokenResp.negState == NULL
     730           0 :         || *resp.u.negTokenResp.negState != accept_completed)
     731             :     {
     732           0 :         free_NegotiationToken(&resp);
     733           0 :         return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM,
     734           0 :                                        GSS_S_BAD_MECH, (*minor_status = EINVAL),
     735             :                                        "NegToken not accept_completed");
     736             :     }
     737             : 
     738           0 :     if (resp.u.negTokenResp.mechListMIC) {
     739           0 :         major_status = _gss_spnego_verify_mechtypes_mic(minor_status, ctx,
     740             :                                                         resp.u.negTokenResp.mechListMIC);
     741           0 :     } else if (ctx->flags.safe_omit == 0) {
     742           0 :         free_NegotiationToken(&resp);
     743           0 :         return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM,
     744           0 :                                        GSS_S_BAD_MECH, (*minor_status = EINVAL),
     745             :                                        "Waiting for MIC, but its missing in server request");
     746             :     } else {
     747           0 :         major_status = GSS_S_COMPLETE;
     748             :     }
     749             : 
     750           0 :     free_NegotiationToken(&resp);
     751           0 :     if (major_status != GSS_S_COMPLETE)
     752           0 :         return major_status;
     753             : 
     754           0 :     ctx->flags.verified_mic = 1;
     755           0 :     ctx->initiator_state = step_completed;
     756             : 
     757           0 :     if (ret_flags)
     758           0 :         *ret_flags = ctx->mech_flags;
     759           0 :     if (time_rec)
     760           0 :         *time_rec = ctx->mech_time_rec;
     761             : 
     762           0 :     *minor_status = 0;
     763           0 :     return GSS_S_COMPLETE;
     764             : }
     765             : 
     766             : static OM_uint32
     767           0 : step_completed(OM_uint32 * minor_status,
     768             :                gss_const_cred_id_t cred,
     769             :                gssspnego_ctx ctx,
     770             :                gss_const_name_t name,
     771             :                gss_const_OID mech_type,
     772             :                OM_uint32 req_flags,
     773             :                OM_uint32 time_req,
     774             :                const gss_channel_bindings_t input_chan_bindings,
     775             :                gss_const_buffer_t input_token,
     776             :                gss_buffer_t output_token,
     777             :                OM_uint32 * ret_flags,
     778             :                OM_uint32 * time_rec)
     779             : {
     780           0 :     return gss_mg_set_error_string(GSS_SPNEGO_MECHANISM,
     781           0 :                                    GSS_S_BAD_STATUS, (*minor_status = EINVAL),
     782             :                                    "SPNEGO called got ISC call one too many");
     783             : }
     784             : 
     785             : OM_uint32 GSSAPI_CALLCONV
     786           0 : _gss_spnego_init_sec_context(OM_uint32 * minor_status,
     787             :                              gss_const_cred_id_t initiator_cred_handle,
     788             :                              gss_ctx_id_t * context_handle,
     789             :                              gss_const_name_t target_name,
     790             :                              const gss_OID mech_type,
     791             :                              OM_uint32 req_flags,
     792             :                              OM_uint32 time_req,
     793             :                              const gss_channel_bindings_t input_chan_bindings,
     794             :                              const gss_buffer_t input_token,
     795             :                              gss_OID * actual_mech_type,
     796             :                              gss_buffer_t output_token,
     797             :                              OM_uint32 * ret_flags,
     798             :                              OM_uint32 * time_rec)
     799             : {
     800           0 :     gssspnego_ctx ctx;
     801           0 :     OM_uint32 ret;
     802             : 
     803           0 :     if (*context_handle == GSS_C_NO_CONTEXT) {
     804           0 :         ret = _gss_spnego_alloc_sec_context(minor_status, context_handle);
     805           0 :         if (GSS_ERROR(ret))
     806           0 :             return ret;
     807             : 
     808           0 :         ctx = (gssspnego_ctx)*context_handle;
     809             : 
     810           0 :         ctx->initiator_state = spnego_initial;
     811             :     } else {
     812           0 :         ctx = (gssspnego_ctx)*context_handle;
     813             :     }
     814             : 
     815             : 
     816           0 :     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
     817             : 
     818           0 :     do {
     819           0 :         ret = ctx->initiator_state(minor_status, initiator_cred_handle, ctx, target_name,
     820             :                                    mech_type, req_flags, time_req, input_chan_bindings, input_token,
     821             :                                    output_token, ret_flags, time_rec);
     822             : 
     823           0 :     } while (ret == GSS_S_COMPLETE &&
     824           0 :              ctx->initiator_state != step_completed &&
     825           0 :              output_token->length == 0);
     826             : 
     827             :     /* destroy context in case of error */
     828           0 :     if (GSS_ERROR(ret)) {
     829           0 :         OM_uint32 junk;
     830           0 :         _gss_spnego_internal_delete_sec_context(&junk, context_handle, GSS_C_NO_BUFFER);
     831             :     } else {
     832             : 
     833           0 :         HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
     834             : 
     835           0 :         if (actual_mech_type)
     836           0 :             *actual_mech_type = ctx->negotiated_mech_type;
     837             :     }
     838             : 
     839           0 :     return ret;
     840             : }
     841             : 

Generated by: LCOV version 1.14