LCOV - code coverage report
Current view: top level - auth/gensec - spnego.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 736 865 85.1 %
Date: 2021-08-25 13:27:56 Functions: 31 31 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    RFC2478 Compliant SPNEGO implementation
       5             : 
       6             :    Copyright (C) Jim McDonough <jmcd@us.ibm.com>      2003
       7             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
       8             :    Copyright (C) Stefan Metzmacher <metze@samba.org>  2004-2008
       9             : 
      10             :    This program is free software; you can redistribute it and/or modify
      11             :    it under the terms of the GNU General Public License as published by
      12             :    the Free Software Foundation; either version 3 of the License, or
      13             :    (at your option) any later version.
      14             : 
      15             :    This program is distributed in the hope that it will be useful,
      16             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :    GNU General Public License for more details.
      19             : 
      20             : 
      21             :    You should have received a copy of the GNU General Public License
      22             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      23             : */
      24             : 
      25             : #include "includes.h"
      26             : #include <tevent.h>
      27             : #include "lib/util/tevent_ntstatus.h"
      28             : #include "../libcli/auth/spnego.h"
      29             : #include "librpc/gen_ndr/ndr_dcerpc.h"
      30             : #include "auth/credentials/credentials.h"
      31             : #include "auth/gensec/gensec.h"
      32             : #include "auth/gensec/gensec_internal.h"
      33             : #include "param/param.h"
      34             : #include "lib/util/asn1.h"
      35             : #include "lib/util/base64.h"
      36             : 
      37             : #undef DBGC_CLASS
      38             : #define DBGC_CLASS DBGC_AUTH
      39             : 
      40             : #undef strcasecmp
      41             : 
      42             : _PUBLIC_ NTSTATUS gensec_spnego_init(TALLOC_CTX *ctx);
      43             : 
      44             : enum spnego_state_position {
      45             :         SPNEGO_SERVER_START,
      46             :         SPNEGO_CLIENT_START,
      47             :         SPNEGO_SERVER_TARG,
      48             :         SPNEGO_CLIENT_TARG,
      49             :         SPNEGO_FALLBACK,
      50             :         SPNEGO_DONE
      51             : };
      52             : 
      53             : struct spnego_state;
      54             : struct spnego_neg_ops;
      55             : struct spnego_neg_state;
      56             : 
      57             : struct spnego_neg_state {
      58             :         const struct spnego_neg_ops *ops;
      59             :         const struct gensec_security_ops_wrapper *all_sec;
      60             :         size_t all_idx;
      61             :         const char * const *mech_types;
      62             :         size_t mech_idx;
      63             : };
      64             : 
      65             : struct spnego_neg_ops {
      66             :         const char *name;
      67             :         /*
      68             :          * The start hook does the initial processing on the incoming paket and
      69             :          * may starts the first possible subcontext. It indicates that
      70             :          * gensec_update() is required on the subcontext by returning
      71             :          * NT_STATUS_MORE_PROCESSING_REQUIRED and return something useful in
      72             :          * 'in_next'. Note that 'in_mem_ctx' is just passed as a hint, the
      73             :          * caller should treat 'in_next' as const and don't attempt to free the
      74             :          * content.  NT_STATUS_OK indicates the finish hook should be invoked
      75             :          * directly within the need of gensec_update() on the subcontext.
      76             :          * Every other error indicates an error that's returned to the caller.
      77             :          */
      78             :         NTSTATUS (*start_fn)(struct gensec_security *gensec_security,
      79             :                              struct spnego_state *spnego_state,
      80             :                              struct spnego_neg_state *n,
      81             :                              struct spnego_data *spnego_in,
      82             :                              TALLOC_CTX *in_mem_ctx,
      83             :                              DATA_BLOB *in_next);
      84             :         /*
      85             :          * The step hook processes the result of a failed gensec_update() and
      86             :          * can decide to ignore a failure and continue the negotiation by
      87             :          * setting up the next possible subcontext. It indicates that
      88             :          * gensec_update() is required on the subcontext by returning
      89             :          * NT_STATUS_MORE_PROCESSING_REQUIRED and return something useful in
      90             :          * 'in_next'. Note that 'in_mem_ctx' is just passed as a hint, the
      91             :          * caller should treat 'in_next' as const and don't attempt to free the
      92             :          * content.  NT_STATUS_OK indicates the finish hook should be invoked
      93             :          * directly within the need of gensec_update() on the subcontext.
      94             :          * Every other error indicates an error that's returned to the caller.
      95             :          */
      96             :         NTSTATUS (*step_fn)(struct gensec_security *gensec_security,
      97             :                             struct spnego_state *spnego_state,
      98             :                             struct spnego_neg_state *n,
      99             :                             struct spnego_data *spnego_in,
     100             :                             NTSTATUS last_status,
     101             :                             TALLOC_CTX *in_mem_ctx,
     102             :                             DATA_BLOB *in_next);
     103             :         /*
     104             :          * The finish hook processes the result of a successful gensec_update()
     105             :          * (NT_STATUS_OK or NT_STATUS_MORE_PROCESSING_REQUIRED). It forms the
     106             :          * response pdu that will be returned from the toplevel gensec_update()
     107             :          * together with NT_STATUS_OK or NT_STATUS_MORE_PROCESSING_REQUIRED. It
     108             :          * may also alter the state machine to prepare receiving the next pdu
     109             :          * from the peer.
     110             :          */
     111             :         NTSTATUS (*finish_fn)(struct gensec_security *gensec_security,
     112             :                               struct spnego_state *spnego_state,
     113             :                               struct spnego_neg_state *n,
     114             :                               struct spnego_data *spnego_in,
     115             :                               NTSTATUS sub_status,
     116             :                               const DATA_BLOB sub_out,
     117             :                               TALLOC_CTX *out_mem_ctx,
     118             :                               DATA_BLOB *out);
     119             : };
     120             : 
     121             : struct spnego_state {
     122             :         enum spnego_message_type expected_packet;
     123             :         enum spnego_state_position state_position;
     124             :         struct gensec_security *sub_sec_security;
     125             :         bool sub_sec_ready;
     126             : 
     127             :         const char *neg_oid;
     128             : 
     129             :         DATA_BLOB mech_types;
     130             :         size_t num_targs;
     131             :         bool downgraded;
     132             :         bool mic_requested;
     133             :         bool needs_mic_sign;
     134             :         bool needs_mic_check;
     135             :         bool may_skip_mic_check;
     136             :         bool done_mic_check;
     137             : 
     138             :         bool simulate_w2k;
     139             :         bool no_optimistic;
     140             : 
     141             :         /*
     142             :          * The following is used to implement
     143             :          * the update token fragmentation
     144             :          */
     145             :         size_t in_needed;
     146             :         DATA_BLOB in_frag;
     147             :         size_t out_max_length;
     148             :         DATA_BLOB out_frag;
     149             :         NTSTATUS out_status;
     150             : };
     151             : 
     152      267827 : static struct spnego_neg_state *gensec_spnego_neg_state(TALLOC_CTX *mem_ctx,
     153             :                 const struct spnego_neg_ops *ops)
     154             : {
     155      271167 :         struct spnego_neg_state *n = NULL;
     156             : 
     157      271167 :         n = talloc_zero(mem_ctx, struct spnego_neg_state);
     158      271167 :         if (n == NULL) {
     159           0 :                 return NULL;
     160             :         }
     161      271167 :         n->ops = ops;
     162             : 
     163      267827 :         return n;
     164             : }
     165             : 
     166       20555 : static void gensec_spnego_reset_sub_sec(struct spnego_state *spnego_state)
     167             : {
     168       20555 :         spnego_state->sub_sec_ready = false;
     169       20555 :         TALLOC_FREE(spnego_state->sub_sec_security);
     170       20555 : }
     171             : 
     172       55988 : static NTSTATUS gensec_spnego_client_start(struct gensec_security *gensec_security)
     173             : {
     174             :         struct spnego_state *spnego_state;
     175             : 
     176       55988 :         spnego_state = talloc_zero(gensec_security, struct spnego_state);
     177       55988 :         if (!spnego_state) {
     178           0 :                 return NT_STATUS_NO_MEMORY;
     179             :         }
     180             : 
     181       55988 :         spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT;
     182       55988 :         spnego_state->state_position = SPNEGO_CLIENT_START;
     183       55988 :         spnego_state->sub_sec_security = NULL;
     184       55988 :         spnego_state->sub_sec_ready = false;
     185       55988 :         spnego_state->mech_types = data_blob_null;
     186       55988 :         spnego_state->out_max_length = gensec_max_update_size(gensec_security);
     187       55988 :         spnego_state->out_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
     188             : 
     189       55988 :         spnego_state->simulate_w2k = gensec_setting_bool(gensec_security->settings,
     190             :                                                 "spnego", "simulate_w2k", false);
     191       55988 :         spnego_state->no_optimistic = gensec_setting_bool(gensec_security->settings,
     192             :                                                           "spnego",
     193             :                                                           "client_no_optimistic",
     194             :                                                           false);
     195             : 
     196       55988 :         gensec_security->private_data = spnego_state;
     197       55988 :         return NT_STATUS_OK;
     198             : }
     199             : 
     200       99344 : static NTSTATUS gensec_spnego_server_start(struct gensec_security *gensec_security)
     201             : {
     202             :         struct spnego_state *spnego_state;
     203             : 
     204       99344 :         spnego_state = talloc_zero(gensec_security, struct spnego_state);
     205       99344 :         if (!spnego_state) {
     206           0 :                 return NT_STATUS_NO_MEMORY;
     207             :         }
     208             : 
     209       99344 :         spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT;
     210       99344 :         spnego_state->state_position = SPNEGO_SERVER_START;
     211       99344 :         spnego_state->sub_sec_security = NULL;
     212       99344 :         spnego_state->sub_sec_ready = false;
     213       99344 :         spnego_state->mech_types = data_blob_null;
     214       99344 :         spnego_state->out_max_length = gensec_max_update_size(gensec_security);
     215       99344 :         spnego_state->out_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
     216             : 
     217       99344 :         spnego_state->simulate_w2k = gensec_setting_bool(gensec_security->settings,
     218             :                                                 "spnego", "simulate_w2k", false);
     219             : 
     220       99344 :         gensec_security->private_data = spnego_state;
     221       99344 :         return NT_STATUS_OK;
     222             : }
     223             : 
     224             : /** Fallback to another GENSEC mechanism, based on magic strings 
     225             :  *
     226             :  * This is the 'fallback' case, where we don't get SPNEGO, and have to
     227             :  * try all the other options (and hope they all have a magic string
     228             :  * they check)
     229             : */
     230             : 
     231         327 : static NTSTATUS gensec_spnego_server_try_fallback(struct gensec_security *gensec_security, 
     232             :                                                   struct spnego_state *spnego_state,
     233             :                                                   TALLOC_CTX *mem_ctx,
     234             :                                                   const DATA_BLOB in)
     235             : {
     236             :         int i,j;
     237             :         const struct gensec_security_ops **all_ops;
     238             : 
     239         327 :         all_ops = gensec_security_mechs(gensec_security, mem_ctx);
     240             : 
     241        1040 :         for (i=0; all_ops && all_ops[i]; i++) {
     242             :                 bool is_spnego;
     243             :                 NTSTATUS nt_status;
     244             : 
     245        1040 :                 if (gensec_security != NULL &&
     246         520 :                     !gensec_security_ops_enabled(all_ops[i], gensec_security))
     247             :                 {
     248         244 :                         continue;
     249             :                 }
     250             : 
     251         469 :                 if (!all_ops[i]->oid) {
     252          75 :                         continue;
     253             :                 }
     254             : 
     255         394 :                 is_spnego = false;
     256        1051 :                 for (j=0; all_ops[i]->oid[j]; j++) {
     257         657 :                         if (strcasecmp(GENSEC_OID_SPNEGO,all_ops[i]->oid[j]) == 0) {
     258          26 :                                 is_spnego = true;
     259             :                         }
     260             :                 }
     261         394 :                 if (is_spnego) {
     262          26 :                         continue;
     263             :                 }
     264             : 
     265         368 :                 if (!all_ops[i]->magic) {
     266           0 :                         continue;
     267             :                 }
     268             : 
     269         368 :                 nt_status = all_ops[i]->magic(gensec_security, &in);
     270         368 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     271          41 :                         continue;
     272             :                 }
     273             : 
     274         327 :                 spnego_state->state_position = SPNEGO_FALLBACK;
     275             : 
     276         327 :                 nt_status = gensec_subcontext_start(spnego_state, 
     277             :                                                     gensec_security, 
     278             :                                                     &spnego_state->sub_sec_security);
     279             : 
     280         327 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     281         327 :                         return nt_status;
     282             :                 }
     283             :                 /* select the sub context */
     284         327 :                 nt_status = gensec_start_mech_by_ops(spnego_state->sub_sec_security,
     285         327 :                                                      all_ops[i]);
     286         327 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     287           0 :                         return nt_status;
     288             :                 }
     289             : 
     290         327 :                 return NT_STATUS_OK;
     291             :         }
     292           0 :         DEBUG(1, ("Failed to parse SPNEGO request\n"));
     293           0 :         return NT_STATUS_INVALID_PARAMETER;
     294             : }
     295             : 
     296       69328 : static NTSTATUS gensec_spnego_create_negTokenInit_start(
     297             :                                         struct gensec_security *gensec_security,
     298             :                                         struct spnego_state *spnego_state,
     299             :                                         struct spnego_neg_state *n,
     300             :                                         struct spnego_data *spnego_in,
     301             :                                         TALLOC_CTX *in_mem_ctx,
     302             :                                         DATA_BLOB *in_next)
     303             : {
     304       69328 :         n->mech_idx = 0;
     305       69328 :         n->mech_types = gensec_security_oids(gensec_security, n,
     306             :                                              GENSEC_OID_SPNEGO);
     307       69328 :         if (n->mech_types == NULL) {
     308           0 :                 DBG_WARNING("gensec_security_oids() failed\n");
     309           0 :                 return NT_STATUS_NO_MEMORY;
     310             :         }
     311             : 
     312       69328 :         n->all_idx = 0;
     313       69328 :         n->all_sec = gensec_security_by_oid_list(gensec_security,
     314             :                                                  n, n->mech_types,
     315             :                                                  GENSEC_OID_SPNEGO);
     316       69328 :         if (n->all_sec == NULL) {
     317           0 :                 DBG_WARNING("gensec_security_by_oid_list() failed\n");
     318           0 :                 return NT_STATUS_NO_MEMORY;
     319             :         }
     320             : 
     321      138656 :         return n->ops->step_fn(gensec_security, spnego_state, n,
     322       69328 :                                spnego_in, NT_STATUS_OK, in_mem_ctx, in_next);
     323             : }
     324             : 
     325       69517 : static NTSTATUS gensec_spnego_create_negTokenInit_step(
     326             :                                         struct gensec_security *gensec_security,
     327             :                                         struct spnego_state *spnego_state,
     328             :                                         struct spnego_neg_state *n,
     329             :                                         struct spnego_data *spnego_in,
     330             :                                         NTSTATUS last_status,
     331             :                                         TALLOC_CTX *in_mem_ctx,
     332             :                                         DATA_BLOB *in_next)
     333             : {
     334       69517 :         if (!NT_STATUS_IS_OK(last_status)) {
     335         189 :                 const struct gensec_security_ops_wrapper *cur_sec =
     336         189 :                         &n->all_sec[n->all_idx];
     337         189 :                 const struct gensec_security_ops_wrapper *next_sec = NULL;
     338         189 :                 const char *next = NULL;
     339         189 :                 const char *principal = NULL;
     340         189 :                 int dbg_level = DBGLVL_WARNING;
     341         189 :                 NTSTATUS status = last_status;
     342             : 
     343         189 :                 if (cur_sec[1].op != NULL) {
     344          44 :                         next_sec = &cur_sec[1];
     345             :                 }
     346             : 
     347         189 :                 if (next_sec != NULL) {
     348          44 :                         next = next_sec->op->name;
     349          44 :                         dbg_level = DBGLVL_NOTICE;
     350             :                 }
     351             : 
     352         189 :                 if (gensec_security->target.principal != NULL) {
     353           0 :                         principal = gensec_security->target.principal;
     354         378 :                 } else if (gensec_security->target.service != NULL &&
     355         189 :                            gensec_security->target.hostname != NULL)
     356             :                 {
     357         189 :                         principal = talloc_asprintf(spnego_state->sub_sec_security,
     358             :                                                     "%s/%s",
     359             :                                                     gensec_security->target.service,
     360             :                                                     gensec_security->target.hostname);
     361             :                 } else {
     362           0 :                         principal = gensec_security->target.hostname;
     363             :                 }
     364             : 
     365         189 :                 DBG_PREFIX(dbg_level, (
     366             :                            "%s: creating NEG_TOKEN_INIT for %s failed "
     367             :                            "(next[%s]): %s\n", cur_sec->op->name,
     368             :                            principal, next, nt_errstr(status)));
     369             : 
     370         189 :                 if (next == NULL) {
     371             :                         /*
     372             :                          * A hard error without a possible fallback.
     373             :                          */
     374         145 :                         return status;
     375             :                 }
     376             : 
     377             :                 /*
     378             :                  * Pretend we never started it
     379             :                  */
     380          44 :                 gensec_spnego_reset_sub_sec(spnego_state);
     381             : 
     382             :                 /*
     383             :                  * And try the next one...
     384             :                  */
     385          44 :                 n->all_idx += 1;
     386             :         }
     387             : 
     388      141158 :         for (; n->all_sec[n->all_idx].op != NULL; n->all_idx++) {
     389       71148 :                 const struct gensec_security_ops_wrapper *cur_sec =
     390       70006 :                         &n->all_sec[n->all_idx];
     391             :                 NTSTATUS status;
     392             : 
     393       71148 :                 status = gensec_subcontext_start(spnego_state,
     394             :                                                  gensec_security,
     395             :                                                  &spnego_state->sub_sec_security);
     396       71148 :                 if (!NT_STATUS_IS_OK(status)) {
     397       68228 :                         return status;
     398             :                 }
     399             : 
     400             :                 /* select the sub context */
     401       71148 :                 status = gensec_start_mech_by_ops(spnego_state->sub_sec_security,
     402             :                                                   cur_sec->op);
     403       71148 :                 if (!NT_STATUS_IS_OK(status)) {
     404        1778 :                         gensec_spnego_reset_sub_sec(spnego_state);
     405        1778 :                         continue;
     406             :                 }
     407             : 
     408             :                 /* In the client, try and produce the first (optimistic) packet */
     409       69370 :                 if (spnego_state->state_position == SPNEGO_CLIENT_START) {
     410       23961 :                         *in_next = data_blob_null;
     411       23961 :                         return NT_STATUS_MORE_PROCESSING_REQUIRED;
     412             :                 }
     413             : 
     414       45409 :                 *in_next = data_blob_null;
     415       45409 :                 return NT_STATUS_OK;
     416             :         }
     417             : 
     418           2 :         DBG_WARNING("Failed to setup SPNEGO negTokenInit request\n");
     419           2 :         return NT_STATUS_INVALID_PARAMETER;
     420             : }
     421             : 
     422       69181 : static NTSTATUS gensec_spnego_create_negTokenInit_finish(
     423             :                                         struct gensec_security *gensec_security,
     424             :                                         struct spnego_state *spnego_state,
     425             :                                         struct spnego_neg_state *n,
     426             :                                         struct spnego_data *spnego_in,
     427             :                                         NTSTATUS sub_status,
     428             :                                         const DATA_BLOB sub_out,
     429             :                                         TALLOC_CTX *out_mem_ctx,
     430             :                                         DATA_BLOB *out)
     431             : {
     432       69181 :         const struct gensec_security_ops_wrapper *cur_sec =
     433       69181 :                         &n->all_sec[n->all_idx];
     434             :         struct spnego_data spnego_out;
     435             :         bool ok;
     436             : 
     437       69181 :         spnego_out.type = SPNEGO_NEG_TOKEN_INIT;
     438             : 
     439       69181 :         n->mech_types = gensec_security_oids_from_ops_wrapped(n, cur_sec);
     440       69181 :         if (n->mech_types == NULL) {
     441           0 :                 DBG_WARNING("gensec_security_oids_from_ops_wrapped() failed\n");
     442           0 :                 return NT_STATUS_NO_MEMORY;
     443             :         }
     444             : 
     445       69181 :         ok = spnego_write_mech_types(spnego_state,
     446             :                                      n->mech_types,
     447             :                                      &spnego_state->mech_types);
     448       69181 :         if (!ok) {
     449           0 :                 DBG_ERR("Failed to write mechTypes\n");
     450           0 :                 return NT_STATUS_NO_MEMORY;
     451             :         }
     452             : 
     453             :         /* List the remaining mechs as options */
     454       69181 :         spnego_out.negTokenInit.mechTypes = n->mech_types;
     455       69181 :         spnego_out.negTokenInit.reqFlags = data_blob_null;
     456       69181 :         spnego_out.negTokenInit.reqFlagsPadding = 0;
     457             : 
     458       69181 :         if (spnego_state->state_position == SPNEGO_SERVER_START) {
     459             :                 spnego_out.negTokenInit.mechListMIC
     460       45409 :                         = data_blob_string_const(ADS_IGNORE_PRINCIPAL);
     461             :         } else {
     462       23772 :                 spnego_out.negTokenInit.mechListMIC = data_blob_null;
     463             :         }
     464             : 
     465       69181 :         spnego_out.negTokenInit.mechToken = sub_out;
     466             : 
     467       69181 :         if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
     468           0 :                 DBG_ERR("Failed to write NEG_TOKEN_INIT\n");
     469           0 :                 return NT_STATUS_INVALID_PARAMETER;
     470             :         }
     471             : 
     472             :         /*
     473             :          * Note that 'cur_sec' is temporary memory, but
     474             :          * cur_sec->oid points to a const string in the
     475             :          * backends gensec_security_ops structure.
     476             :          */
     477       69181 :         spnego_state->neg_oid = cur_sec->oid;
     478             : 
     479             :         /* set next state */
     480       69181 :         if (spnego_state->state_position == SPNEGO_SERVER_START) {
     481       45409 :                 spnego_state->state_position = SPNEGO_SERVER_START;
     482       45409 :                 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT;
     483             :         } else {
     484       23772 :                 spnego_state->state_position = SPNEGO_CLIENT_TARG;
     485       23772 :                 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
     486             :         }
     487             : 
     488       69181 :         return NT_STATUS_MORE_PROCESSING_REQUIRED;
     489             : }
     490             : 
     491             : static const struct spnego_neg_ops gensec_spnego_create_negTokenInit_ops = {
     492             :         .name      = "create_negTokenInit",
     493             :         .start_fn  = gensec_spnego_create_negTokenInit_start,
     494             :         .step_fn   = gensec_spnego_create_negTokenInit_step,
     495             :         .finish_fn = gensec_spnego_create_negTokenInit_finish,
     496             : };
     497             : 
     498       32068 : static NTSTATUS gensec_spnego_client_negTokenInit_start(
     499             :                                         struct gensec_security *gensec_security,
     500             :                                         struct spnego_state *spnego_state,
     501             :                                         struct spnego_neg_state *n,
     502             :                                         struct spnego_data *spnego_in,
     503             :                                         TALLOC_CTX *in_mem_ctx,
     504             :                                         DATA_BLOB *in_next)
     505             : {
     506       32068 :         const char *tp = NULL;
     507             : 
     508             :         /* The server offers a list of mechanisms */
     509             : 
     510       32068 :         tp = spnego_in->negTokenInit.targetPrincipal;
     511       32068 :         if (tp != NULL && strcmp(tp, ADS_IGNORE_PRINCIPAL) != 0) {
     512           0 :                 DBG_INFO("Server claims it's principal name is %s\n", tp);
     513           0 :                 if (lpcfg_client_use_spnego_principal(gensec_security->settings->lp_ctx)) {
     514           0 :                         gensec_set_target_principal(gensec_security, tp);
     515             :                 }
     516             :         }
     517             : 
     518       32068 :         n->mech_idx = 0;
     519             : 
     520             :         /* Do not use server mech list as it isn't protected. Instead, get all
     521             :          * supported mechs (excluding SPNEGO). */
     522       32068 :         n->mech_types = gensec_security_oids(gensec_security, n,
     523             :                                              GENSEC_OID_SPNEGO);
     524       32068 :         if (n->mech_types == NULL) {
     525           0 :                 return NT_STATUS_INVALID_PARAMETER;
     526             :         }
     527             : 
     528       32068 :         n->all_idx = 0;
     529       32068 :         n->all_sec = gensec_security_by_oid_list(gensec_security,
     530             :                                                  n, n->mech_types,
     531             :                                                  GENSEC_OID_SPNEGO);
     532       32068 :         if (n->all_sec == NULL) {
     533           0 :                 DBG_WARNING("gensec_security_by_oid_list() failed\n");
     534           0 :                 return NT_STATUS_INVALID_PARAMETER;
     535             :         }
     536             : 
     537       64136 :         return n->ops->step_fn(gensec_security, spnego_state, n,
     538       32068 :                                spnego_in, NT_STATUS_OK, in_mem_ctx, in_next);
     539             : }
     540             : 
     541       32466 : static NTSTATUS gensec_spnego_client_negTokenInit_step(
     542             :                                         struct gensec_security *gensec_security,
     543             :                                         struct spnego_state *spnego_state,
     544             :                                         struct spnego_neg_state *n,
     545             :                                         struct spnego_data *spnego_in,
     546             :                                         NTSTATUS last_status,
     547             :                                         TALLOC_CTX *in_mem_ctx,
     548             :                                         DATA_BLOB *in_next)
     549             : {
     550       32466 :         if (!NT_STATUS_IS_OK(last_status)) {
     551         398 :                 const struct gensec_security_ops_wrapper *cur_sec =
     552         398 :                         &n->all_sec[n->all_idx];
     553         398 :                 const struct gensec_security_ops_wrapper *next_sec = NULL;
     554         398 :                 const char *next = NULL;
     555         398 :                 const char *principal = NULL;
     556         398 :                 int dbg_level = DBGLVL_WARNING;
     557         398 :                 bool allow_fallback = false;
     558         398 :                 NTSTATUS status = last_status;
     559             : 
     560         398 :                 if (cur_sec[1].op != NULL) {
     561         380 :                         next_sec = &cur_sec[1];
     562             :                 }
     563             : 
     564             :                 /*
     565             :                  * it is likely that a NULL input token will
     566             :                  * not be liked by most server mechs, but if
     567             :                  * we are in the client, we want the first
     568             :                  * update packet to be able to abort the use
     569             :                  * of this mech
     570             :                  */
     571         786 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
     572         776 :                     NT_STATUS_EQUAL(status, NT_STATUS_INVALID_ACCOUNT_NAME) ||
     573         776 :                     NT_STATUS_EQUAL(status, NT_STATUS_INVALID_COMPUTER_NAME) ||
     574         776 :                     NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN) ||
     575         410 :                     NT_STATUS_EQUAL(status, NT_STATUS_NO_LOGON_SERVERS) ||
     576          44 :                     NT_STATUS_EQUAL(status, NT_STATUS_TIME_DIFFERENCE_AT_DC) ||
     577          22 :                     NT_STATUS_EQUAL(status, NT_STATUS_CANT_ACCESS_DOMAIN_INFO))
     578             :                 {
     579         376 :                         allow_fallback = true;
     580             :                 }
     581             : 
     582         398 :                 if (allow_fallback && next_sec != NULL) {
     583         370 :                         next = next_sec->op->name;
     584         370 :                         dbg_level = DBGLVL_NOTICE;
     585             :                 }
     586             : 
     587         398 :                 if (gensec_security->target.principal != NULL) {
     588           0 :                         principal = gensec_security->target.principal;
     589         796 :                 } else if (gensec_security->target.service != NULL &&
     590         398 :                            gensec_security->target.hostname != NULL)
     591             :                 {
     592         398 :                         principal = talloc_asprintf(spnego_state->sub_sec_security,
     593             :                                                     "%s/%s",
     594             :                                                     gensec_security->target.service,
     595             :                                                     gensec_security->target.hostname);
     596             :                 } else {
     597           0 :                         principal = gensec_security->target.hostname;
     598             :                 }
     599             : 
     600         398 :                 DBG_PREFIX(dbg_level, (
     601             :                            "%s: creating NEG_TOKEN_INIT for %s failed "
     602             :                            "(next[%s]): %s\n", cur_sec->op->name,
     603             :                            principal, next, nt_errstr(status)));
     604             : 
     605         398 :                 if (next == NULL) {
     606             :                         /*
     607             :                          * A hard error without a possible fallback.
     608             :                          */
     609          28 :                         return status;
     610             :                 }
     611             : 
     612             :                 /*
     613             :                  * Pretend we never started it.
     614             :                  */
     615         370 :                 gensec_spnego_reset_sub_sec(spnego_state);
     616             : 
     617             :                 /*
     618             :                  * And try the next one...
     619             :                  */
     620         370 :                 n->all_idx += 1;
     621             :         }
     622             : 
     623      101078 :         for (; n->all_sec[n->all_idx].op != NULL; n->all_idx++) {
     624       50792 :                 const struct gensec_security_ops_wrapper *cur_sec =
     625       50270 :                         &n->all_sec[n->all_idx];
     626             :                 NTSTATUS status;
     627             : 
     628       50792 :                 status = gensec_subcontext_start(spnego_state,
     629             :                                                  gensec_security,
     630             :                                                  &spnego_state->sub_sec_security);
     631       50792 :                 if (!NT_STATUS_IS_OK(status)) {
     632       31908 :                         return status;
     633             :                 }
     634             : 
     635             :                 /* select the sub context */
     636       50792 :                 status = gensec_start_mech_by_ops(spnego_state->sub_sec_security,
     637             :                                                   cur_sec->op);
     638       50792 :                 if (!NT_STATUS_IS_OK(status)) {
     639       18362 :                         gensec_spnego_reset_sub_sec(spnego_state);
     640       18362 :                         continue;
     641             :                 }
     642             : 
     643             :                 /*
     644             :                  * Note that 'cur_sec' is temporary memory, but
     645             :                  * cur_sec->oid points to a const string in the
     646             :                  * backends gensec_security_ops structure.
     647             :                  */
     648       32430 :                 spnego_state->neg_oid = cur_sec->oid;
     649             : 
     650             :                 /*
     651             :                  * As client we don't use an optimistic token from the server.
     652             :                  * But try to produce one for the server.
     653             :                  */
     654       32430 :                 *in_next = data_blob_null;
     655       32430 :                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
     656             :         }
     657             : 
     658           8 :         DBG_WARNING("Could not find a suitable mechtype in NEG_TOKEN_INIT\n");
     659           8 :         return NT_STATUS_INVALID_PARAMETER;
     660             : }
     661             : 
     662       32032 : static NTSTATUS gensec_spnego_client_negTokenInit_finish(
     663             :                                         struct gensec_security *gensec_security,
     664             :                                         struct spnego_state *spnego_state,
     665             :                                         struct spnego_neg_state *n,
     666             :                                         struct spnego_data *spnego_in,
     667             :                                         NTSTATUS sub_status,
     668             :                                         const DATA_BLOB sub_out,
     669             :                                         TALLOC_CTX *out_mem_ctx,
     670             :                                         DATA_BLOB *out)
     671             : {
     672             :         struct spnego_data spnego_out;
     673       32032 :         const char * const *mech_types = NULL;
     674             :         bool ok;
     675             : 
     676       32032 :         if (n->mech_types == NULL) {
     677           0 :                 DBG_WARNING("No mech_types list\n");
     678           0 :                 return NT_STATUS_INVALID_PARAMETER;
     679             :         }
     680             : 
     681       68958 :         for (mech_types = n->mech_types; *mech_types != NULL; mech_types++) {
     682       69480 :                 int cmp = strcmp(*mech_types, spnego_state->neg_oid);
     683             : 
     684       69480 :                 if (cmp == 0) {
     685       31510 :                         break;
     686             :                 }
     687             :         }
     688             : 
     689       32032 :         if (*mech_types == NULL) {
     690           0 :                 DBG_ERR("Can't find selected sub mechanism in mech_types\n");
     691           0 :                 return NT_STATUS_INVALID_PARAMETER;
     692             :         }
     693             : 
     694             :         /* compose reply */
     695       32032 :         spnego_out.type = SPNEGO_NEG_TOKEN_INIT;
     696       32032 :         spnego_out.negTokenInit.mechTypes = mech_types;
     697       32032 :         spnego_out.negTokenInit.reqFlags = data_blob_null;
     698       32032 :         spnego_out.negTokenInit.reqFlagsPadding = 0;
     699       32032 :         spnego_out.negTokenInit.mechListMIC = data_blob_null;
     700       32032 :         spnego_out.negTokenInit.mechToken = sub_out;
     701             : 
     702       32032 :         if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
     703           0 :                 DBG_ERR("Failed to write SPNEGO reply to NEG_TOKEN_INIT\n");
     704           0 :                 return NT_STATUS_INVALID_PARAMETER;
     705             :         }
     706             : 
     707       32032 :         ok = spnego_write_mech_types(spnego_state,
     708             :                                      mech_types,
     709             :                                      &spnego_state->mech_types);
     710       32032 :         if (!ok) {
     711           0 :                 DBG_ERR("failed to write mechTypes\n");
     712           0 :                 return NT_STATUS_NO_MEMORY;
     713             :         }
     714             : 
     715             :         /* set next state */
     716       32032 :         spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
     717       32032 :         spnego_state->state_position = SPNEGO_CLIENT_TARG;
     718             : 
     719       32032 :         return NT_STATUS_MORE_PROCESSING_REQUIRED;
     720             : }
     721             : 
     722             : static const struct spnego_neg_ops gensec_spnego_client_negTokenInit_ops = {
     723             :         .name      = "client_negTokenInit",
     724             :         .start_fn  = gensec_spnego_client_negTokenInit_start,
     725             :         .step_fn   = gensec_spnego_client_negTokenInit_step,
     726             :         .finish_fn = gensec_spnego_client_negTokenInit_finish,
     727             : };
     728             : 
     729       84286 : static NTSTATUS gensec_spnego_client_negTokenTarg_start(
     730             :                                         struct gensec_security *gensec_security,
     731             :                                         struct spnego_state *spnego_state,
     732             :                                         struct spnego_neg_state *n,
     733             :                                         struct spnego_data *spnego_in,
     734             :                                         TALLOC_CTX *in_mem_ctx,
     735             :                                         DATA_BLOB *in_next)
     736             : {
     737       84286 :         struct spnego_negTokenTarg *ta = &spnego_in->negTokenTarg;
     738             :         NTSTATUS status;
     739             : 
     740       84286 :         spnego_state->num_targs++;
     741             : 
     742       84286 :         if (ta->negResult == SPNEGO_REJECT) {
     743           0 :                 return NT_STATUS_LOGON_FAILURE;
     744             :         }
     745             : 
     746       84286 :         if (ta->negResult == SPNEGO_REQUEST_MIC) {
     747           1 :                 spnego_state->mic_requested = true;
     748             :         }
     749             : 
     750       84286 :         if (ta->mechListMIC.length > 0) {
     751       31325 :                 DATA_BLOB *m = &ta->mechListMIC;
     752       31325 :                 const DATA_BLOB *r = &ta->responseToken;
     753             : 
     754             :                 /*
     755             :                  * Windows 2000 has a bug, it repeats the
     756             :                  * responseToken in the mechListMIC field.
     757             :                  */
     758       31325 :                 if (m->length == r->length) {
     759             :                         int cmp;
     760             : 
     761        3816 :                         cmp = memcmp(m->data, r->data, m->length);
     762        3816 :                         if (cmp == 0) {
     763        3816 :                                 data_blob_free(m);
     764             :                         }
     765             :                 }
     766             :         }
     767             : 
     768             :         /* Server didn't like our choice of mech, and chose something else */
     769      135931 :         if (((ta->negResult == SPNEGO_ACCEPT_INCOMPLETE) ||
     770       83547 :              (ta->negResult == SPNEGO_REQUEST_MIC)) &&
     771       63804 :             ta->supportedMech != NULL &&
     772       31902 :             strcmp(ta->supportedMech, spnego_state->neg_oid) != 0)
     773             :         {
     774           1 :                 const char *client_mech = NULL;
     775           1 :                 const char *client_oid = NULL;
     776           1 :                 const char *server_mech = NULL;
     777           1 :                 const char *server_oid = NULL;
     778             : 
     779           1 :                 client_mech = gensec_get_name_by_oid(gensec_security,
     780             :                                                      spnego_state->neg_oid);
     781           1 :                 client_oid = spnego_state->neg_oid;
     782           1 :                 server_mech = gensec_get_name_by_oid(gensec_security,
     783             :                                                      ta->supportedMech);
     784           1 :                 server_oid = ta->supportedMech;
     785             : 
     786           1 :                 DBG_NOTICE("client preferred mech (%s[%s]) not accepted, "
     787             :                            "server wants: %s[%s]\n",
     788             :                            client_mech, client_oid, server_mech, server_oid);
     789             : 
     790           1 :                 spnego_state->downgraded = true;
     791           1 :                 gensec_spnego_reset_sub_sec(spnego_state);
     792             : 
     793           1 :                 status = gensec_subcontext_start(spnego_state,
     794             :                                                  gensec_security,
     795             :                                                  &spnego_state->sub_sec_security);
     796           1 :                 if (!NT_STATUS_IS_OK(status)) {
     797           0 :                         return status;
     798             :                 }
     799             : 
     800             :                 /* select the sub context */
     801           1 :                 status = gensec_start_mech_by_oid(spnego_state->sub_sec_security,
     802             :                                                   ta->supportedMech);
     803           1 :                 if (!NT_STATUS_IS_OK(status)) {
     804           0 :                         return status;
     805             :                 }
     806             : 
     807           1 :                 spnego_state->neg_oid = talloc_strdup(spnego_state,
     808             :                                         ta->supportedMech);
     809           1 :                 if (spnego_state->neg_oid == NULL) {
     810           0 :                         return NT_STATUS_NO_MEMORY;
     811             :                 }
     812             :         }
     813             : 
     814       84286 :         if (ta->mechListMIC.length > 0) {
     815       27509 :                 if (spnego_state->sub_sec_ready) {
     816       27506 :                         spnego_state->needs_mic_check = true;
     817             :                 }
     818             :         }
     819             : 
     820       84286 :         if (spnego_state->needs_mic_check) {
     821       27509 :                 if (ta->responseToken.length != 0) {
     822           0 :                         DBG_WARNING("non empty response token not expected\n");
     823           0 :                         return NT_STATUS_INVALID_PARAMETER;
     824             :                 }
     825             : 
     826       27509 :                 if (ta->mechListMIC.length == 0
     827           3 :                     && spnego_state->may_skip_mic_check) {
     828             :                         /*
     829             :                          * In this case we don't require
     830             :                          * a mechListMIC from the server.
     831             :                          *
     832             :                          * This works around bugs in the Azure
     833             :                          * and Apple spnego implementations.
     834             :                          *
     835             :                          * See
     836             :                          * https://bugzilla.samba.org/show_bug.cgi?id=11994
     837             :                          */
     838           2 :                         spnego_state->needs_mic_check = false;
     839           2 :                         return NT_STATUS_OK;
     840             :                 }
     841             : 
     842       82425 :                 status = gensec_check_packet(spnego_state->sub_sec_security,
     843       27411 :                                              spnego_state->mech_types.data,
     844             :                                              spnego_state->mech_types.length,
     845       27507 :                                              spnego_state->mech_types.data,
     846             :                                              spnego_state->mech_types.length,
     847       27507 :                                              &ta->mechListMIC);
     848       27507 :                 if (!NT_STATUS_IS_OK(status)) {
     849           1 :                         DBG_WARNING("failed to verify mechListMIC: %s\n",
     850             :                                     nt_errstr(status));
     851           1 :                         return status;
     852             :                 }
     853       27506 :                 spnego_state->needs_mic_check = false;
     854       27506 :                 spnego_state->done_mic_check = true;
     855       27506 :                 return NT_STATUS_OK;
     856             :         }
     857             : 
     858       56777 :         if (!spnego_state->sub_sec_ready) {
     859       54033 :                 *in_next = ta->responseToken;
     860       54033 :                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
     861             :         }
     862             : 
     863        2744 :         return NT_STATUS_OK;
     864             : }
     865             : 
     866           4 : static NTSTATUS gensec_spnego_client_negTokenTarg_step(
     867             :                                         struct gensec_security *gensec_security,
     868             :                                         struct spnego_state *spnego_state,
     869             :                                         struct spnego_neg_state *n,
     870             :                                         struct spnego_data *spnego_in,
     871             :                                         NTSTATUS last_status,
     872             :                                         TALLOC_CTX *in_mem_ctx,
     873             :                                         DATA_BLOB *in_next)
     874             : {
     875           4 :         if (GENSEC_UPDATE_IS_NTERROR(last_status)) {
     876           4 :                 DBG_WARNING("SPNEGO(%s) login failed: %s\n",
     877             :                             spnego_state->sub_sec_security->ops->name,
     878             :                             nt_errstr(last_status));
     879           4 :                 return last_status;
     880             :         }
     881             : 
     882             :         /*
     883             :          * This should never be reached!
     884             :          * The step function is only called on errors!
     885             :          */
     886           0 :         smb_panic(__location__);
     887             :         return NT_STATUS_INTERNAL_ERROR;
     888             : }
     889             : 
     890       84281 : static NTSTATUS gensec_spnego_client_negTokenTarg_finish(
     891             :                                         struct gensec_security *gensec_security,
     892             :                                         struct spnego_state *spnego_state,
     893             :                                         struct spnego_neg_state *n,
     894             :                                         struct spnego_data *spnego_in,
     895             :                                         NTSTATUS sub_status,
     896             :                                         const DATA_BLOB sub_out,
     897             :                                         TALLOC_CTX *out_mem_ctx,
     898             :                                         DATA_BLOB *out)
     899             : {
     900       84281 :         const struct spnego_negTokenTarg *ta =
     901             :                 &spnego_in->negTokenTarg;
     902       84281 :         DATA_BLOB mech_list_mic = data_blob_null;
     903             :         NTSTATUS status;
     904             :         struct spnego_data spnego_out;
     905             : 
     906       84281 :         if (!spnego_state->sub_sec_ready) {
     907             :                 /*
     908             :                  * We're not yet ready to deal with signatures.
     909             :                  */
     910           6 :                 goto client_response;
     911             :         }
     912             : 
     913       84275 :         if (spnego_state->done_mic_check) {
     914             :                 /*
     915             :                  * We already checked the mic,
     916             :                  * either the in last round here
     917             :                  * in gensec_spnego_client_negTokenTarg_finish()
     918             :                  * or during this round in
     919             :                  * gensec_spnego_client_negTokenTarg_start().
     920             :                  *
     921             :                  * Both cases we're sure we don't have to
     922             :                  * call gensec_sign_packet().
     923             :                  */
     924       27413 :                 goto client_response;
     925             :         }
     926             : 
     927       56766 :         if (spnego_state->may_skip_mic_check) {
     928             :                 /*
     929             :                  * This can only be set during
     930             :                  * the last round here in
     931             :                  * gensec_spnego_client_negTokenTarg_finish()
     932             :                  * below. And during this round
     933             :                  * we already passed the checks in
     934             :                  * gensec_spnego_client_negTokenTarg_start().
     935             :                  *
     936             :                  * So we need to skip to deal with
     937             :                  * any signatures now.
     938             :                  */
     939        1014 :                 goto client_response;
     940             :         }
     941             : 
     942       55010 :         if (!spnego_state->done_mic_check) {
     943       55750 :                 bool have_sign = true;
     944       55750 :                 bool new_spnego = false;
     945             : 
     946       55750 :                 have_sign = gensec_have_feature(spnego_state->sub_sec_security,
     947             :                                                 GENSEC_FEATURE_SIGN);
     948       55750 :                 if (spnego_state->simulate_w2k) {
     949         421 :                         have_sign = false;
     950             :                 }
     951       55750 :                 new_spnego = gensec_have_feature(spnego_state->sub_sec_security,
     952             :                                                  GENSEC_FEATURE_NEW_SPNEGO);
     953             : 
     954       55750 :                 switch (ta->negResult) {
     955       23858 :                 case SPNEGO_ACCEPT_COMPLETED:
     956             :                 case SPNEGO_NONE_RESULT:
     957       23858 :                         if (spnego_state->num_targs == 1) {
     958             :                                 /*
     959             :                                  * the first exchange doesn't require
     960             :                                  * verification
     961             :                                  */
     962       22325 :                                 new_spnego = false;
     963             :                         }
     964             : 
     965       23216 :                         break;
     966             : 
     967       31892 :                 case SPNEGO_ACCEPT_INCOMPLETE:
     968       31892 :                         if (ta->mechListMIC.length > 0) {
     969           3 :                                 new_spnego = true;
     970           3 :                                 break;
     971             :                         }
     972             : 
     973       31889 :                         if (spnego_state->downgraded) {
     974             :                                 /*
     975             :                                  * A downgrade should be protected if
     976             :                                  * supported
     977             :                                  */
     978           1 :                                 break;
     979             :                         }
     980             : 
     981             :                         /*
     982             :                          * The caller may just asked for
     983             :                          * GENSEC_FEATURE_SESSION_KEY, this
     984             :                          * is only reflected in the want_features.
     985             :                          *
     986             :                          * As it will imply
     987             :                          * gensec_have_features(GENSEC_FEATURE_SIGN)
     988             :                          * to return true.
     989             :                          */
     990       31888 :                         if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
     991       11782 :                                 break;
     992             :                         }
     993       20010 :                         if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
     994         264 :                                 break;
     995             :                         }
     996             :                         /*
     997             :                          * Here we're sure our preferred mech was
     998             :                          * selected by the server and our caller doesn't
     999             :                          * need GENSEC_FEATURE_SIGN nor
    1000             :                          * GENSEC_FEATURE_SEAL support.
    1001             :                          *
    1002             :                          * In this case we don't require
    1003             :                          * a mechListMIC from the server.
    1004             :                          *
    1005             :                          * This works around bugs in the Azure
    1006             :                          * and Apple spnego implementations.
    1007             :                          *
    1008             :                          * See
    1009             :                          * https://bugzilla.samba.org/show_bug.cgi?id=11994
    1010             :                          */
    1011       19746 :                         spnego_state->may_skip_mic_check = true;
    1012       19746 :                         break;
    1013             : 
    1014           0 :                 case SPNEGO_REQUEST_MIC:
    1015           0 :                         if (ta->mechListMIC.length > 0) {
    1016           0 :                                 new_spnego = true;
    1017             :                         }
    1018           0 :                         break;
    1019           0 :                 default:
    1020           0 :                         break;
    1021             :                 }
    1022             : 
    1023       55846 :                 if (spnego_state->mic_requested) {
    1024           1 :                         if (have_sign) {
    1025           1 :                                 new_spnego = true;
    1026             :                         }
    1027             :                 }
    1028             : 
    1029       55750 :                 if (have_sign && new_spnego) {
    1030       29231 :                         spnego_state->needs_mic_check = true;
    1031       29231 :                         spnego_state->needs_mic_sign = true;
    1032             :                 }
    1033             :         }
    1034             : 
    1035       55750 :         if (ta->mechListMIC.length > 0) {
    1036           9 :                 status = gensec_check_packet(spnego_state->sub_sec_security,
    1037           3 :                                              spnego_state->mech_types.data,
    1038             :                                              spnego_state->mech_types.length,
    1039           3 :                                              spnego_state->mech_types.data,
    1040             :                                              spnego_state->mech_types.length,
    1041             :                                              &ta->mechListMIC);
    1042           3 :                 if (!NT_STATUS_IS_OK(status)) {
    1043           0 :                         DBG_WARNING("failed to verify mechListMIC: %s\n",
    1044             :                                     nt_errstr(status));
    1045           0 :                         return status;
    1046             :                 }
    1047           3 :                 spnego_state->needs_mic_check = false;
    1048           3 :                 spnego_state->done_mic_check = true;
    1049             :         }
    1050             : 
    1051       55750 :         if (spnego_state->needs_mic_sign) {
    1052       87597 :                 status = gensec_sign_packet(spnego_state->sub_sec_security,
    1053             :                                             n,
    1054       29135 :                                             spnego_state->mech_types.data,
    1055             :                                             spnego_state->mech_types.length,
    1056       29231 :                                             spnego_state->mech_types.data,
    1057             :                                             spnego_state->mech_types.length,
    1058             :                                             &mech_list_mic);
    1059       29231 :                 if (!NT_STATUS_IS_OK(status)) {
    1060           0 :                         DBG_WARNING("failed to sign mechListMIC: %s\n",
    1061             :                                     nt_errstr(status));
    1062           0 :                         return status;
    1063             :                 }
    1064       29231 :                 spnego_state->needs_mic_sign = false;
    1065             :         }
    1066             : 
    1067      110898 :  client_response:
    1068       84281 :         if (sub_out.length == 0 && mech_list_mic.length == 0) {
    1069       52383 :                 *out = data_blob_null;
    1070             : 
    1071       52383 :                 if (!spnego_state->sub_sec_ready) {
    1072             :                         /* somethings wrong here... */
    1073           0 :                         DBG_ERR("gensec_update not ready without output\n");
    1074           0 :                         return NT_STATUS_INTERNAL_ERROR;
    1075             :                 }
    1076             : 
    1077       52383 :                 if (ta->negResult != SPNEGO_ACCEPT_COMPLETED) {
    1078             :                         /* unless of course it did not accept */
    1079           0 :                         DBG_WARNING("gensec_update ok but not accepted\n");
    1080           0 :                         return NT_STATUS_INVALID_PARAMETER;
    1081             :                 }
    1082             : 
    1083       52383 :                 if (!spnego_state->needs_mic_check) {
    1084       52383 :                         spnego_state->state_position = SPNEGO_DONE;
    1085       52383 :                         return NT_STATUS_OK;
    1086             :                 }
    1087             :         }
    1088             : 
    1089             :         /* compose reply */
    1090       31898 :         spnego_out.type = SPNEGO_NEG_TOKEN_TARG;
    1091       31898 :         spnego_out.negTokenTarg.negResult = SPNEGO_NONE_RESULT;
    1092       31898 :         spnego_out.negTokenTarg.supportedMech = NULL;
    1093       31898 :         spnego_out.negTokenTarg.responseToken = sub_out;
    1094       31898 :         spnego_out.negTokenTarg.mechListMIC = mech_list_mic;
    1095             : 
    1096       31898 :         if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
    1097           0 :                 DBG_WARNING("Failed to write NEG_TOKEN_TARG\n");
    1098           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1099             :         }
    1100             : 
    1101       31898 :         spnego_state->num_targs++;
    1102             : 
    1103             :         /* set next state */
    1104       31898 :         spnego_state->state_position = SPNEGO_CLIENT_TARG;
    1105       31898 :         spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
    1106             : 
    1107       31898 :         return NT_STATUS_MORE_PROCESSING_REQUIRED;
    1108             : }
    1109             : 
    1110             : static const struct spnego_neg_ops gensec_spnego_client_negTokenTarg_ops = {
    1111             :         .name      = "client_negTokenTarg",
    1112             :         .start_fn  = gensec_spnego_client_negTokenTarg_start,
    1113             :         .step_fn   = gensec_spnego_client_negTokenTarg_step,
    1114             :         .finish_fn = gensec_spnego_client_negTokenTarg_finish,
    1115             : };
    1116             : 
    1117             : /** create a server negTokenTarg 
    1118             :  *
    1119             :  * This is the case, where the client is the first one who sends data
    1120             : */
    1121             : 
    1122       83738 : static NTSTATUS gensec_spnego_server_response(struct spnego_state *spnego_state,
    1123             :                                               TALLOC_CTX *out_mem_ctx,
    1124             :                                               NTSTATUS nt_status,
    1125             :                                               const DATA_BLOB unwrapped_out,
    1126             :                                               DATA_BLOB mech_list_mic,
    1127             :                                               DATA_BLOB *out)
    1128             : {
    1129             :         struct spnego_data spnego_out;
    1130             : 
    1131             :         /* compose reply */
    1132       83738 :         spnego_out.type = SPNEGO_NEG_TOKEN_TARG;
    1133       83738 :         spnego_out.negTokenTarg.responseToken = unwrapped_out;
    1134       83738 :         spnego_out.negTokenTarg.mechListMIC = mech_list_mic;
    1135       83738 :         spnego_out.negTokenTarg.supportedMech = NULL;
    1136             : 
    1137       83738 :         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {   
    1138       31489 :                 spnego_out.negTokenTarg.supportedMech = spnego_state->neg_oid;
    1139       31489 :                 if (spnego_state->mic_requested) {
    1140           1 :                         spnego_out.negTokenTarg.negResult = SPNEGO_REQUEST_MIC;
    1141           1 :                         spnego_state->mic_requested = false;
    1142             :                 } else {
    1143       31488 :                         spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
    1144             :                 }
    1145       31489 :                 spnego_state->state_position = SPNEGO_SERVER_TARG;
    1146       52249 :         } else if (NT_STATUS_IS_OK(nt_status)) {
    1147       52249 :                 if (unwrapped_out.data) {
    1148       22324 :                         spnego_out.negTokenTarg.supportedMech = spnego_state->neg_oid;
    1149             :                 }
    1150       52249 :                 spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED;
    1151       52249 :                 spnego_state->state_position = SPNEGO_DONE;
    1152             :         }
    1153             : 
    1154       83738 :         if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
    1155           0 :                 DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n"));
    1156           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1157             :         }
    1158             : 
    1159       83738 :         spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
    1160       83738 :         spnego_state->num_targs++;
    1161             : 
    1162       83738 :         return nt_status;
    1163             : }
    1164             : 
    1165       54008 : static NTSTATUS gensec_spnego_server_negTokenInit_start(
    1166             :                                         struct gensec_security *gensec_security,
    1167             :                                         struct spnego_state *spnego_state,
    1168             :                                         struct spnego_neg_state *n,
    1169             :                                         struct spnego_data *spnego_in,
    1170             :                                         TALLOC_CTX *in_mem_ctx,
    1171             :                                         DATA_BLOB *in_next)
    1172             : {
    1173             :         bool ok;
    1174             : 
    1175       54008 :         n->mech_idx = 0;
    1176       54008 :         n->mech_types = spnego_in->negTokenInit.mechTypes;
    1177       54008 :         if (n->mech_types == NULL) {
    1178           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1179             :         }
    1180             : 
    1181       54008 :         n->all_idx = 0;
    1182       54008 :         n->all_sec = gensec_security_by_oid_list(gensec_security,
    1183             :                                                  n, n->mech_types,
    1184             :                                                  GENSEC_OID_SPNEGO);
    1185       54008 :         if (n->all_sec == NULL) {
    1186           0 :                 DBG_WARNING("gensec_security_by_oid_list() failed\n");
    1187           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1188             :         }
    1189             : 
    1190       54008 :         ok = spnego_write_mech_types(spnego_state,
    1191             :                                      n->mech_types,
    1192             :                                      &spnego_state->mech_types);
    1193       54008 :         if (!ok) {
    1194           0 :                 DBG_ERR("Failed to write mechTypes\n");
    1195           0 :                 return NT_STATUS_NO_MEMORY;
    1196             :         }
    1197             : 
    1198      108016 :         return n->ops->step_fn(gensec_security, spnego_state, n,
    1199       54008 :                                spnego_in, NT_STATUS_OK, in_mem_ctx, in_next);
    1200             : }
    1201             : 
    1202       54013 : static NTSTATUS gensec_spnego_server_negTokenInit_step(
    1203             :                                         struct gensec_security *gensec_security,
    1204             :                                         struct spnego_state *spnego_state,
    1205             :                                         struct spnego_neg_state *n,
    1206             :                                         struct spnego_data *spnego_in,
    1207             :                                         NTSTATUS last_status,
    1208             :                                         TALLOC_CTX *in_mem_ctx,
    1209             :                                         DATA_BLOB *in_next)
    1210             : {
    1211       54013 :         if (!NT_STATUS_IS_OK(last_status)) {
    1212           5 :                 const struct gensec_security_ops_wrapper *cur_sec =
    1213           5 :                         &n->all_sec[n->all_idx];
    1214           5 :                 const char *next_mech = n->mech_types[n->mech_idx+1];
    1215           5 :                 const struct gensec_security_ops_wrapper *next_sec = NULL;
    1216           5 :                 const char *next = NULL;
    1217           5 :                 int dbg_level = DBGLVL_WARNING;
    1218           5 :                 bool allow_fallback = false;
    1219           5 :                 NTSTATUS status = last_status;
    1220             :                 size_t i;
    1221             : 
    1222          16 :                 for (i = 0; next_mech != NULL && n->all_sec[i].op != NULL; i++) {
    1223           3 :                         if (strcmp(next_mech, n->all_sec[i].oid) != 0) {
    1224           3 :                                 continue;
    1225             :                         }
    1226             : 
    1227           0 :                         next_sec = &n->all_sec[i];
    1228           0 :                         break;
    1229             :                 }
    1230             : 
    1231          10 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
    1232           5 :                     NT_STATUS_EQUAL(status, NT_STATUS_CANT_ACCESS_DOMAIN_INFO))
    1233             :                 {
    1234           0 :                         allow_fallback = true;
    1235             :                 }
    1236             : 
    1237           5 :                 if (allow_fallback && next_sec != NULL) {
    1238           0 :                         next = next_sec->op->name;
    1239           0 :                         dbg_level = DBGLVL_NOTICE;
    1240             :                 }
    1241             : 
    1242           5 :                 DBG_PREFIX(dbg_level, (
    1243             :                            "%s: parsing NEG_TOKEN_INIT content failed "
    1244             :                            "(next[%s]): %s\n", cur_sec->op->name,
    1245             :                            next, nt_errstr(status)));
    1246             : 
    1247           5 :                 if (next == NULL) {
    1248             :                         /*
    1249             :                          * A hard error without a possible fallback.
    1250             :                          */
    1251           5 :                         return status;
    1252             :                 }
    1253             : 
    1254             :                 /*
    1255             :                  * Pretend we never started it
    1256             :                  */
    1257           0 :                 gensec_spnego_reset_sub_sec(spnego_state);
    1258             : 
    1259             :                 /*
    1260             :                  * And try the next one, based on the clients
    1261             :                  * mech type list...
    1262             :                  */
    1263           0 :                 n->mech_idx += 1;
    1264             :         }
    1265             : 
    1266             :         /*
    1267             :          * we always reset all_idx here, as the negotiation is
    1268             :          * done via mech_idx!
    1269             :          */
    1270       54008 :         n->all_idx = 0;
    1271             : 
    1272      107288 :         for (; n->mech_types[n->mech_idx] != NULL; n->mech_idx++) {
    1273       54012 :                 const char *cur_mech = n->mech_types[n->mech_idx];
    1274       54012 :                 const struct gensec_security_ops_wrapper *cur_sec = NULL;
    1275             :                 NTSTATUS status;
    1276       54012 :                 DATA_BLOB sub_in = data_blob_null;
    1277             :                 size_t i;
    1278             : 
    1279      108028 :                 for (i = 0; n->all_sec[i].op != NULL; i++) {
    1280       54008 :                         if (strcmp(cur_mech, n->all_sec[i].oid) != 0) {
    1281           2 :                                 continue;
    1282             :                         }
    1283             : 
    1284       54006 :                         cur_sec = &n->all_sec[i];
    1285       54006 :                         n->all_idx = i;
    1286       54006 :                         break;
    1287             :                 }
    1288             : 
    1289       54012 :                 if (cur_sec == NULL) {
    1290          12 :                         continue;
    1291             :                 }
    1292             : 
    1293       54006 :                 status = gensec_subcontext_start(spnego_state,
    1294             :                                                  gensec_security,
    1295             :                                                  &spnego_state->sub_sec_security);
    1296       54006 :                 if (!NT_STATUS_IS_OK(status)) {
    1297       53266 :                         return status;
    1298             :                 }
    1299             : 
    1300             :                 /* select the sub context */
    1301       54006 :                 status = gensec_start_mech_by_ops(spnego_state->sub_sec_security,
    1302             :                                                   cur_sec->op);
    1303       54006 :                 if (!NT_STATUS_IS_OK(status)) {
    1304             :                         /*
    1305             :                          * Pretend we never started it
    1306             :                          */
    1307           0 :                         gensec_spnego_reset_sub_sec(spnego_state);
    1308           0 :                         continue;
    1309             :                 }
    1310             : 
    1311       54006 :                 if (n->mech_idx == 0) {
    1312             :                         /*
    1313             :                          * We can use the optimistic token.
    1314             :                          */
    1315       54005 :                         sub_in = spnego_in->negTokenInit.mechToken;
    1316             :                 } else {
    1317             :                         /*
    1318             :                          * Indicate the downgrade and request a
    1319             :                          * mic.
    1320             :                          */
    1321           1 :                         spnego_state->downgraded = true;
    1322           1 :                         spnego_state->mic_requested = true;
    1323             :                 }
    1324             : 
    1325       54006 :                 if (sub_in.length == 0) {
    1326           6 :                         spnego_state->no_optimistic = true;
    1327             :                 }
    1328             : 
    1329             :                 /*
    1330             :                  * Note that 'cur_sec' is temporary memory, but
    1331             :                  * cur_sec->oid points to a const string in the
    1332             :                  * backends gensec_security_ops structure.
    1333             :                  */
    1334       54006 :                 spnego_state->neg_oid = cur_sec->oid;
    1335             : 
    1336             :                 /* we need some content from the mech */
    1337       54006 :                 *in_next = sub_in;
    1338       54006 :                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
    1339             :         }
    1340             : 
    1341           2 :         DBG_WARNING("Could not find a suitable mechtype in NEG_TOKEN_INIT\n");
    1342           2 :         return NT_STATUS_INVALID_PARAMETER;
    1343             : }
    1344             : 
    1345       54001 : static NTSTATUS gensec_spnego_server_negTokenInit_finish(
    1346             :                                         struct gensec_security *gensec_security,
    1347             :                                         struct spnego_state *spnego_state,
    1348             :                                         struct spnego_neg_state *n,
    1349             :                                         struct spnego_data *spnego_in,
    1350             :                                         NTSTATUS sub_status,
    1351             :                                         const DATA_BLOB sub_out,
    1352             :                                         TALLOC_CTX *out_mem_ctx,
    1353             :                                         DATA_BLOB *out)
    1354             : {
    1355       54001 :         DATA_BLOB mech_list_mic = data_blob_null;
    1356             : 
    1357       54001 :         if (spnego_state->simulate_w2k) {
    1358             :                 /*
    1359             :                  * Windows 2000 returns the unwrapped token
    1360             :                  * also in the mech_list_mic field.
    1361             :                  *
    1362             :                  * In order to verify our client code,
    1363             :                  * we need a way to have a server with this
    1364             :                  * broken behaviour
    1365             :                  */
    1366        3892 :                 mech_list_mic = sub_out;
    1367             :         }
    1368             : 
    1369       54001 :         return gensec_spnego_server_response(spnego_state,
    1370             :                                              out_mem_ctx,
    1371             :                                              sub_status,
    1372             :                                              sub_out,
    1373             :                                              mech_list_mic,
    1374             :                                              out);
    1375             : }
    1376             : 
    1377             : static const struct spnego_neg_ops gensec_spnego_server_negTokenInit_ops = {
    1378             :         .name      = "server_negTokenInit",
    1379             :         .start_fn  = gensec_spnego_server_negTokenInit_start,
    1380             :         .step_fn   = gensec_spnego_server_negTokenInit_step,
    1381             :         .finish_fn = gensec_spnego_server_negTokenInit_finish,
    1382             : };
    1383             : 
    1384       31477 : static NTSTATUS gensec_spnego_server_negTokenTarg_start(
    1385             :                                         struct gensec_security *gensec_security,
    1386             :                                         struct spnego_state *spnego_state,
    1387             :                                         struct spnego_neg_state *n,
    1388             :                                         struct spnego_data *spnego_in,
    1389             :                                         TALLOC_CTX *in_mem_ctx,
    1390             :                                         DATA_BLOB *in_next)
    1391             : {
    1392       31477 :         const struct spnego_negTokenTarg *ta = &spnego_in->negTokenTarg;
    1393             :         NTSTATUS status;
    1394             : 
    1395       31477 :         spnego_state->num_targs++;
    1396             : 
    1397       31477 :         if (spnego_state->sub_sec_security == NULL) {
    1398           0 :                 DBG_ERR("SPNEGO: Did not setup a mech in NEG_TOKEN_INIT\n");
    1399           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1400             :         }
    1401             : 
    1402       31477 :         if (spnego_state->needs_mic_check) {
    1403           3 :                 if (ta->responseToken.length != 0) {
    1404           0 :                         DBG_WARNING("non empty response token not expected\n");
    1405           0 :                         return NT_STATUS_INVALID_PARAMETER;
    1406             :                 }
    1407             : 
    1408           9 :                 status = gensec_check_packet(spnego_state->sub_sec_security,
    1409           3 :                                              spnego_state->mech_types.data,
    1410             :                                              spnego_state->mech_types.length,
    1411           3 :                                              spnego_state->mech_types.data,
    1412             :                                              spnego_state->mech_types.length,
    1413             :                                              &ta->mechListMIC);
    1414           3 :                 if (!NT_STATUS_IS_OK(status)) {
    1415           0 :                         DBG_WARNING("failed to verify mechListMIC: %s\n",
    1416             :                                     nt_errstr(status));
    1417           0 :                         return status;
    1418             :                 }
    1419             : 
    1420           3 :                 spnego_state->needs_mic_check = false;
    1421           3 :                 spnego_state->done_mic_check = true;
    1422           3 :                 return NT_STATUS_OK;
    1423             :         }
    1424             : 
    1425       31474 :         if (!spnego_state->sub_sec_ready) {
    1426       31474 :                 *in_next = ta->responseToken;
    1427       31474 :                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
    1428             :         }
    1429             : 
    1430           0 :         return NT_STATUS_OK;
    1431             : }
    1432             : 
    1433        1740 : static NTSTATUS gensec_spnego_server_negTokenTarg_step(
    1434             :                                         struct gensec_security *gensec_security,
    1435             :                                         struct spnego_state *spnego_state,
    1436             :                                         struct spnego_neg_state *n,
    1437             :                                         struct spnego_data *spnego_in,
    1438             :                                         NTSTATUS last_status,
    1439             :                                         TALLOC_CTX *in_mem_ctx,
    1440             :                                         DATA_BLOB *in_next)
    1441             : {
    1442        1740 :         if (GENSEC_UPDATE_IS_NTERROR(last_status)) {
    1443        1740 :                 DBG_NOTICE("SPNEGO(%s) login failed: %s\n",
    1444             :                            spnego_state->sub_sec_security->ops->name,
    1445             :                            nt_errstr(last_status));
    1446        1740 :                 return last_status;
    1447             :         }
    1448             : 
    1449             :         /*
    1450             :          * This should never be reached!
    1451             :          * The step function is only called on errors!
    1452             :          */
    1453           0 :         smb_panic(__location__);
    1454             :         return NT_STATUS_INTERNAL_ERROR;
    1455             : }
    1456             : 
    1457       29737 : static NTSTATUS gensec_spnego_server_negTokenTarg_finish(
    1458             :                                         struct gensec_security *gensec_security,
    1459             :                                         struct spnego_state *spnego_state,
    1460             :                                         struct spnego_neg_state *n,
    1461             :                                         struct spnego_data *spnego_in,
    1462             :                                         NTSTATUS sub_status,
    1463             :                                         const DATA_BLOB sub_out,
    1464             :                                         TALLOC_CTX *out_mem_ctx,
    1465             :                                         DATA_BLOB *out)
    1466             : {
    1467       29737 :         const struct spnego_negTokenTarg *ta = &spnego_in->negTokenTarg;
    1468       29737 :         DATA_BLOB mech_list_mic = data_blob_null;
    1469             :         NTSTATUS status;
    1470       29737 :         bool have_sign = true;
    1471       29737 :         bool new_spnego = false;
    1472             : 
    1473       29737 :         status = sub_status;
    1474             : 
    1475       29737 :         if (!spnego_state->sub_sec_ready) {
    1476             :                 /*
    1477             :                  * We're not yet ready to deal with signatures.
    1478             :                  */
    1479           3 :                 goto server_response;
    1480             :         }
    1481             : 
    1482       29734 :         if (spnego_state->done_mic_check) {
    1483             :                 /*
    1484             :                  * We already checked the mic,
    1485             :                  * either the in last round here
    1486             :                  * in gensec_spnego_server_negTokenTarg_finish()
    1487             :                  * or during this round in
    1488             :                  * gensec_spnego_server_negTokenTarg_start().
    1489             :                  *
    1490             :                  * Both cases we're sure we don't have to
    1491             :                  * call gensec_sign_packet().
    1492             :                  */
    1493           3 :                 goto server_response;
    1494             :         }
    1495             : 
    1496       29731 :         have_sign = gensec_have_feature(spnego_state->sub_sec_security,
    1497             :                                         GENSEC_FEATURE_SIGN);
    1498       29731 :         if (spnego_state->simulate_w2k) {
    1499        1591 :                 have_sign = false;
    1500             :         }
    1501       29731 :         new_spnego = gensec_have_feature(spnego_state->sub_sec_security,
    1502             :                                          GENSEC_FEATURE_NEW_SPNEGO);
    1503       29731 :         if (ta->mechListMIC.length > 0) {
    1504       27127 :                 new_spnego = true;
    1505             :         }
    1506             : 
    1507       29731 :         if (have_sign && new_spnego) {
    1508       27110 :                 spnego_state->needs_mic_check = true;
    1509       27110 :                 spnego_state->needs_mic_sign = true;
    1510             :         }
    1511             : 
    1512       29731 :         if (have_sign && ta->mechListMIC.length > 0) {
    1513       81225 :                 status = gensec_check_packet(spnego_state->sub_sec_security,
    1514       27011 :                                              spnego_state->mech_types.data,
    1515             :                                              spnego_state->mech_types.length,
    1516       27107 :                                              spnego_state->mech_types.data,
    1517             :                                              spnego_state->mech_types.length,
    1518             :                                              &ta->mechListMIC);
    1519       27107 :                 if (!NT_STATUS_IS_OK(status)) {
    1520           0 :                         DBG_WARNING("failed to verify mechListMIC: %s\n",
    1521             :                                     nt_errstr(status));
    1522           0 :                         return status;
    1523             :                 }
    1524             : 
    1525       27107 :                 spnego_state->needs_mic_check = false;
    1526       27107 :                 spnego_state->done_mic_check = true;
    1527             :         }
    1528             : 
    1529       29731 :         if (spnego_state->needs_mic_sign) {
    1530       81234 :                 status = gensec_sign_packet(spnego_state->sub_sec_security,
    1531             :                                             n,
    1532       27014 :                                             spnego_state->mech_types.data,
    1533             :                                             spnego_state->mech_types.length,
    1534       27110 :                                             spnego_state->mech_types.data,
    1535             :                                             spnego_state->mech_types.length,
    1536             :                                             &mech_list_mic);
    1537       27110 :                 if (!NT_STATUS_IS_OK(status)) {
    1538           0 :                         DBG_WARNING("failed to sign mechListMIC: %s\n",
    1539             :                                     nt_errstr(status));
    1540           0 :                         return status;
    1541             :                 }
    1542       27110 :                 spnego_state->needs_mic_sign = false;
    1543             :         }
    1544             : 
    1545       29731 :         if (spnego_state->needs_mic_check) {
    1546           3 :                 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
    1547             :         }
    1548             : 
    1549       59465 :  server_response:
    1550       29737 :         return gensec_spnego_server_response(spnego_state,
    1551             :                                              out_mem_ctx,
    1552             :                                              status,
    1553             :                                              sub_out,
    1554             :                                              mech_list_mic,
    1555             :                                              out);
    1556             : }
    1557             : 
    1558             : static const struct spnego_neg_ops gensec_spnego_server_negTokenTarg_ops = {
    1559             :         .name      = "server_negTokenTarg",
    1560             :         .start_fn  = gensec_spnego_server_negTokenTarg_start,
    1561             :         .step_fn   = gensec_spnego_server_negTokenTarg_step,
    1562             :         .finish_fn = gensec_spnego_server_negTokenTarg_finish,
    1563             : };
    1564             : 
    1565             : struct gensec_spnego_update_state {
    1566             :         struct tevent_context *ev;
    1567             :         struct gensec_security *gensec;
    1568             :         struct spnego_state *spnego;
    1569             : 
    1570             :         DATA_BLOB full_in;
    1571             :         struct spnego_data _spnego_in;
    1572             :         struct spnego_data *spnego_in;
    1573             : 
    1574             :         struct {
    1575             :                 bool needed;
    1576             :                 DATA_BLOB in;
    1577             :                 NTSTATUS status;
    1578             :                 DATA_BLOB out;
    1579             :         } sub;
    1580             : 
    1581             :         struct spnego_neg_state *n;
    1582             : 
    1583             :         NTSTATUS status;
    1584             :         DATA_BLOB out;
    1585             : };
    1586             : 
    1587      545854 : static void gensec_spnego_update_cleanup(struct tevent_req *req,
    1588             :                                          enum tevent_req_state req_state)
    1589             : {
    1590      545854 :         struct gensec_spnego_update_state *state =
    1591      545854 :                 tevent_req_data(req,
    1592             :                 struct gensec_spnego_update_state);
    1593             : 
    1594      545854 :         switch (req_state) {
    1595        1935 :         case TEVENT_REQ_USER_ERROR:
    1596             :         case TEVENT_REQ_TIMED_OUT:
    1597             :         case TEVENT_REQ_NO_MEMORY:
    1598             :                 /*
    1599             :                  * A fatal error, further updates are not allowed.
    1600             :                  */
    1601        1935 :                 state->spnego->state_position = SPNEGO_DONE;
    1602        1935 :                 break;
    1603      537239 :         default:
    1604      537239 :                 break;
    1605             :         }
    1606      545854 : }
    1607             : 
    1608             : static NTSTATUS gensec_spnego_update_in(struct gensec_security *gensec_security,
    1609             :                                         const DATA_BLOB in, TALLOC_CTX *mem_ctx,
    1610             :                                         DATA_BLOB *full_in);
    1611             : static void gensec_spnego_update_pre(struct tevent_req *req);
    1612             : static void gensec_spnego_update_done(struct tevent_req *subreq);
    1613             : static void gensec_spnego_update_post(struct tevent_req *req);
    1614             : static NTSTATUS gensec_spnego_update_out(struct gensec_security *gensec_security,
    1615             :                                          TALLOC_CTX *out_mem_ctx,
    1616             :                                          DATA_BLOB *_out);
    1617             : 
    1618      272927 : static struct tevent_req *gensec_spnego_update_send(TALLOC_CTX *mem_ctx,
    1619             :                                                     struct tevent_context *ev,
    1620             :                                                     struct gensec_security *gensec_security,
    1621             :                                                     const DATA_BLOB in)
    1622             : {
    1623      272927 :         struct spnego_state *spnego_state =
    1624      272927 :                 talloc_get_type_abort(gensec_security->private_data,
    1625             :                 struct spnego_state);
    1626      272927 :         struct tevent_req *req = NULL;
    1627      272927 :         struct gensec_spnego_update_state *state = NULL;
    1628             :         NTSTATUS status;
    1629             :         ssize_t len;
    1630             : 
    1631      272927 :         req = tevent_req_create(mem_ctx, &state,
    1632             :                                 struct gensec_spnego_update_state);
    1633      272927 :         if (req == NULL) {
    1634           0 :                 return NULL;
    1635             :         }
    1636      272927 :         state->ev = ev;
    1637      272927 :         state->gensec = gensec_security;
    1638      272927 :         state->spnego = spnego_state;
    1639      272927 :         tevent_req_set_cleanup_fn(req, gensec_spnego_update_cleanup);
    1640             : 
    1641      272927 :         if (spnego_state->out_frag.length > 0) {
    1642         664 :                 if (in.length > 0) {
    1643           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
    1644           0 :                         return tevent_req_post(req, ev);
    1645             :                 }
    1646             : 
    1647         664 :                 status = gensec_spnego_update_out(gensec_security,
    1648         664 :                                                   state, &state->out);
    1649         664 :                 if (GENSEC_UPDATE_IS_NTERROR(status)) {
    1650           0 :                         tevent_req_nterror(req, status);
    1651           0 :                         return tevent_req_post(req, ev);
    1652             :                 }
    1653             : 
    1654         664 :                 state->status = status;
    1655         664 :                 tevent_req_done(req);
    1656         664 :                 return tevent_req_post(req, ev);
    1657             :         }
    1658             : 
    1659      272263 :         status = gensec_spnego_update_in(gensec_security, in,
    1660      272263 :                                          state, &state->full_in);
    1661      272263 :         state->status = status;
    1662      272263 :         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
    1663         664 :                 tevent_req_done(req);
    1664         664 :                 return tevent_req_post(req, ev);
    1665             :         }
    1666      271599 :         if (tevent_req_nterror(req, status)) {
    1667           0 :                 return tevent_req_post(req, ev);
    1668             :         }
    1669             : 
    1670             :         /* Check if we got a valid SPNEGO blob... */
    1671             : 
    1672      271599 :         switch (spnego_state->state_position) {
    1673         105 :         case SPNEGO_FALLBACK:
    1674         105 :                 break;
    1675             : 
    1676      115763 :         case SPNEGO_CLIENT_TARG:
    1677             :         case SPNEGO_SERVER_TARG:
    1678      115763 :                 if (state->full_in.length == 0) {
    1679           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
    1680           0 :                         return tevent_req_post(req, ev);
    1681             :                 }
    1682             : 
    1683             :                 FALL_THROUGH;
    1684             :         case SPNEGO_CLIENT_START:
    1685             :         case SPNEGO_SERVER_START:
    1686             : 
    1687      271494 :                 if (state->full_in.length == 0) {
    1688             :                         /* create_negTokenInit later */
    1689       68186 :                         break;
    1690             :                 }
    1691             : 
    1692      402134 :                 len = spnego_read_data(state,
    1693      199968 :                                        state->full_in,
    1694      199968 :                                        &state->_spnego_in);
    1695      202166 :                 if (len == -1) {
    1696         327 :                         if (spnego_state->state_position != SPNEGO_SERVER_START) {
    1697           0 :                                 DEBUG(1, ("Invalid SPNEGO request:\n"));
    1698           0 :                                 dump_data(1, state->full_in.data,
    1699           0 :                                           state->full_in.length);
    1700           0 :                                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
    1701           0 :                                 return tevent_req_post(req, ev);
    1702             :                         }
    1703             : 
    1704             :                         /*
    1705             :                          * This is the 'fallback' case, where we don't get
    1706             :                          * SPNEGO, and have to try all the other options (and
    1707             :                          * hope they all have a magic string they check)
    1708             :                          */
    1709         327 :                         status = gensec_spnego_server_try_fallback(gensec_security,
    1710             :                                                                    spnego_state,
    1711             :                                                                    state,
    1712         327 :                                                                    state->full_in);
    1713         327 :                         if (tevent_req_nterror(req, status)) {
    1714           0 :                                 return tevent_req_post(req, ev);
    1715             :                         }
    1716             : 
    1717             :                         /*
    1718             :                          * We'll continue with SPNEGO_FALLBACK below...
    1719             :                          */
    1720         327 :                         break;
    1721             :                 }
    1722      201839 :                 state->spnego_in = &state->_spnego_in;
    1723             : 
    1724             :                 /* OK, so it's real SPNEGO, check the packet's the one we expect */
    1725      201839 :                 if (state->spnego_in->type != spnego_state->expected_packet) {
    1726           0 :                         DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n",
    1727             :                                   state->spnego_in->type,
    1728             :                                   spnego_state->expected_packet));
    1729           0 :                         dump_data(1, state->full_in.data,
    1730           0 :                                   state->full_in.length);
    1731           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
    1732           0 :                         return tevent_req_post(req, ev);
    1733             :                 }
    1734             : 
    1735      199641 :                 break;
    1736             : 
    1737           0 :         default:
    1738           0 :                 smb_panic(__location__);
    1739             :                 return NULL;
    1740             :         }
    1741             : 
    1742      269401 :         gensec_spnego_update_pre(req);
    1743      271599 :         if (!tevent_req_is_in_progress(req)) {
    1744          13 :                 return tevent_req_post(req, ev);
    1745             :         }
    1746             : 
    1747      271586 :         if (state->sub.needed) {
    1748      195911 :                 struct tevent_req *subreq = NULL;
    1749             : 
    1750             :                 /*
    1751             :                  * We may need one more roundtrip...
    1752             :                  */
    1753      195911 :                 subreq = gensec_update_send(state, state->ev,
    1754             :                                             spnego_state->sub_sec_security,
    1755      193581 :                                             state->sub.in);
    1756      195911 :                 if (tevent_req_nomem(subreq, req)) {
    1757           0 :                         return tevent_req_post(req, ev);
    1758             :                 }
    1759      195911 :                 tevent_req_set_callback(subreq,
    1760             :                                         gensec_spnego_update_done,
    1761             :                                         req);
    1762      195911 :                 state->sub.needed = false;
    1763      195911 :                 return req;
    1764             :         }
    1765             : 
    1766       75675 :         gensec_spnego_update_post(req);
    1767       75675 :         if (!tevent_req_is_in_progress(req)) {
    1768       75675 :                 return tevent_req_post(req, ev);
    1769             :         }
    1770             : 
    1771           0 :         return req;
    1772             : }
    1773             : 
    1774      272263 : static NTSTATUS gensec_spnego_update_in(struct gensec_security *gensec_security,
    1775             :                                         const DATA_BLOB in, TALLOC_CTX *mem_ctx,
    1776             :                                         DATA_BLOB *full_in)
    1777             : {
    1778      272263 :         struct spnego_state *spnego_state =
    1779      272263 :                 talloc_get_type_abort(gensec_security->private_data,
    1780             :                 struct spnego_state);
    1781             :         size_t expected;
    1782             :         bool ok;
    1783             : 
    1784      272263 :         *full_in = data_blob_null;
    1785             : 
    1786      272263 :         switch (spnego_state->state_position) {
    1787         105 :         case SPNEGO_FALLBACK:
    1788         105 :                 *full_in = in;
    1789         105 :                 spnego_state->in_needed = 0;
    1790         105 :                 return NT_STATUS_OK;
    1791             : 
    1792      268818 :         case SPNEGO_CLIENT_START:
    1793             :         case SPNEGO_CLIENT_TARG:
    1794             :         case SPNEGO_SERVER_START:
    1795             :         case SPNEGO_SERVER_TARG:
    1796      268818 :                 break;
    1797             : 
    1798           0 :         case SPNEGO_DONE:
    1799             :         default:
    1800           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1801             :         }
    1802             : 
    1803      272158 :         if (spnego_state->in_needed == 0) {
    1804      271494 :                 size_t size = 0;
    1805             :                 int ret;
    1806             : 
    1807             :                 /*
    1808             :                  * try to work out the size of the full
    1809             :                  * input token, it might be fragmented
    1810             :                  */
    1811      271494 :                 ret = asn1_peek_full_tag(in,  ASN1_APPLICATION(0), &size);
    1812      271494 :                 if ((ret != 0) && (ret != EAGAIN)) {
    1813      185196 :                         ret = asn1_peek_full_tag(in, ASN1_CONTEXT(1), &size);
    1814             :                 }
    1815             : 
    1816      271494 :                 if ((ret == 0) || (ret == EAGAIN)) {
    1817      202061 :                         spnego_state->in_needed = size;
    1818             :                 } else {
    1819             :                         /*
    1820             :                          * If it is not an asn1 message
    1821             :                          * just call the next layer.
    1822             :                          */
    1823       69433 :                         spnego_state->in_needed = in.length;
    1824             :                 }
    1825             :         }
    1826             : 
    1827      272158 :         if (spnego_state->in_needed > UINT16_MAX) {
    1828             :                 /*
    1829             :                  * limit the incoming message to 0xFFFF
    1830             :                  * to avoid DoS attacks.
    1831             :                  */
    1832           0 :                 return NT_STATUS_INVALID_BUFFER_SIZE;
    1833             :         }
    1834             : 
    1835      272158 :         if ((spnego_state->in_needed > 0) && (in.length == 0)) {
    1836             :                 /*
    1837             :                  * If we reach this, we know we got at least
    1838             :                  * part of an asn1 message, getting 0 means
    1839             :                  * the remote peer wants us to spin.
    1840             :                  */
    1841           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1842             :         }
    1843             : 
    1844      272158 :         expected = spnego_state->in_needed - spnego_state->in_frag.length;
    1845      272158 :         if (in.length > expected) {
    1846             :                 /*
    1847             :                  * we got more than expected
    1848             :                  */
    1849           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1850             :         }
    1851             : 
    1852      272158 :         if (in.length == spnego_state->in_needed) {
    1853             :                 /*
    1854             :                  * if the in.length contains the full blob
    1855             :                  * we are done.
    1856             :                  *
    1857             :                  * Note: this implies spnego_state->in_frag.length == 0,
    1858             :                  *       but we do not need to check this explicitly
    1859             :                  *       because we already know that we did not get
    1860             :                  *       more than expected.
    1861             :                  */
    1862      271492 :                 *full_in = in;
    1863      271492 :                 spnego_state->in_needed = 0;
    1864      271492 :                 return NT_STATUS_OK;
    1865             :         }
    1866             : 
    1867        1332 :         ok = data_blob_append(spnego_state, &spnego_state->in_frag,
    1868         666 :                               in.data, in.length);
    1869         666 :         if (!ok) {
    1870           0 :                 return NT_STATUS_NO_MEMORY;
    1871             :         }
    1872             : 
    1873         666 :         if (spnego_state->in_needed > spnego_state->in_frag.length) {
    1874         664 :                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
    1875             :         }
    1876             : 
    1877           2 :         *full_in = spnego_state->in_frag;
    1878           2 :         talloc_steal(mem_ctx, full_in->data);
    1879           2 :         spnego_state->in_frag = data_blob_null;
    1880           2 :         spnego_state->in_needed = 0;
    1881           2 :         return NT_STATUS_OK;
    1882             : }
    1883             : 
    1884      271599 : static void gensec_spnego_update_pre(struct tevent_req *req)
    1885             : {
    1886      271599 :         struct gensec_spnego_update_state *state =
    1887      271599 :                 tevent_req_data(req,
    1888             :                 struct gensec_spnego_update_state);
    1889      271599 :         struct spnego_state *spnego_state = state->spnego;
    1890      271599 :         const struct spnego_neg_ops *ops = NULL;
    1891             :         NTSTATUS status;
    1892             : 
    1893      271599 :         state->sub.needed = false;
    1894      271599 :         state->sub.in = data_blob_null;
    1895      271599 :         state->sub.status = NT_STATUS_INTERNAL_ERROR;
    1896      271599 :         state->sub.out = data_blob_null;
    1897             : 
    1898      271599 :         if (spnego_state->state_position == SPNEGO_FALLBACK) {
    1899         432 :                 state->sub.in = state->full_in;
    1900         432 :                 state->full_in = data_blob_null;
    1901         432 :                 state->sub.needed = true;
    1902         877 :                 return;
    1903             :         }
    1904             : 
    1905      271167 :         switch (spnego_state->state_position) {
    1906       55987 :         case SPNEGO_CLIENT_START:
    1907       55987 :                 if (state->spnego_in == NULL) {
    1908             :                         /* client to produce negTokenInit */
    1909       23689 :                         ops = &gensec_spnego_create_negTokenInit_ops;
    1910       23689 :                         break;
    1911             :                 }
    1912             : 
    1913       32068 :                 ops = &gensec_spnego_client_negTokenInit_ops;
    1914       32068 :                 break;
    1915             : 
    1916       83448 :         case SPNEGO_CLIENT_TARG:
    1917       83448 :                 ops = &gensec_spnego_client_negTokenTarg_ops;
    1918       83448 :                 break;
    1919             : 
    1920       99417 :         case SPNEGO_SERVER_START:
    1921       99417 :                 if (state->spnego_in == NULL) {
    1922             :                         /* server to produce negTokenInit */
    1923       44497 :                         ops = &gensec_spnego_create_negTokenInit_ops;
    1924       44497 :                         break;
    1925             :                 }
    1926             : 
    1927       54008 :                 ops = &gensec_spnego_server_negTokenInit_ops;
    1928       54008 :                 break;
    1929             : 
    1930       31477 :         case SPNEGO_SERVER_TARG:
    1931       31477 :                 ops = &gensec_spnego_server_negTokenTarg_ops;
    1932       31477 :                 break;
    1933             : 
    1934           0 :         default:
    1935           0 :                 smb_panic(__location__);
    1936             :                 return;
    1937             :         }
    1938             : 
    1939      271167 :         state->n = gensec_spnego_neg_state(state, ops);
    1940      271167 :         if (tevent_req_nomem(state->n, req)) {
    1941           0 :                 return;
    1942             :         }
    1943             : 
    1944      271167 :         status = ops->start_fn(state->gensec, spnego_state, state->n,
    1945             :                                state->spnego_in, state, &state->sub.in);
    1946      271167 :         if (GENSEC_UPDATE_IS_NTERROR(status)) {
    1947          13 :                 tevent_req_nterror(req, status);
    1948          13 :                 return;
    1949             :         }
    1950             : 
    1951      271154 :         if (NT_STATUS_IS_OK(status)) {
    1952             :                 /*
    1953             :                  * Call finish_fn() with an empty
    1954             :                  * blob and NT_STATUS_OK.
    1955             :                  */
    1956       75664 :                 state->sub.status = NT_STATUS_OK;
    1957      251467 :         } else if (spnego_state->state_position == SPNEGO_CLIENT_START &&
    1958       55977 :                    spnego_state->no_optimistic) {
    1959             :                 /*
    1960             :                  * Skip optimistic token per conf.
    1961             :                  */
    1962           5 :                 state->sub.status = NT_STATUS_MORE_PROCESSING_REQUIRED;
    1963      249491 :         } else if (spnego_state->state_position == SPNEGO_SERVER_START &&
    1964       54012 :                    state->sub.in.length == 0 && spnego_state->no_optimistic) {
    1965             :                 /*
    1966             :                  * If we didn't like the mechanism for which the client sent us
    1967             :                  * an optimistic token, or if he didn't send any, don't call
    1968             :                  * the sub mechanism just yet.
    1969             :                  */
    1970           6 :                 state->sub.status = NT_STATUS_MORE_PROCESSING_REQUIRED;
    1971           6 :                 spnego_state->no_optimistic = false;
    1972             :         } else {
    1973             :                 /*
    1974             :                  * MORE_PROCESSING_REQUIRED =>
    1975             :                  * we need to call gensec_update_send().
    1976             :                  */
    1977      195479 :                 state->sub.needed = true;
    1978             :         }
    1979             : }
    1980             : 
    1981      196325 : static void gensec_spnego_update_done(struct tevent_req *subreq)
    1982             : {
    1983      196325 :         struct tevent_req *req =
    1984      196325 :                 tevent_req_callback_data(subreq,
    1985             :                 struct tevent_req);
    1986      196325 :         struct gensec_spnego_update_state *state =
    1987      196325 :                 tevent_req_data(req,
    1988             :                 struct gensec_spnego_update_state);
    1989      196325 :         struct spnego_state *spnego_state = state->spnego;
    1990             : 
    1991      196325 :         state->sub.status = gensec_update_recv(subreq, state, &state->sub.out);
    1992      196325 :         TALLOC_FREE(subreq);
    1993      196325 :         if (NT_STATUS_IS_OK(state->sub.status)) {
    1994      106793 :                 spnego_state->sub_sec_ready = true;
    1995             :         }
    1996             : 
    1997      196325 :         gensec_spnego_update_post(req);
    1998      196325 : }
    1999             : 
    2000      272000 : static void gensec_spnego_update_post(struct tevent_req *req)
    2001             : {
    2002      272000 :         struct gensec_spnego_update_state *state =
    2003      272000 :                 tevent_req_data(req,
    2004             :                 struct gensec_spnego_update_state);
    2005      272000 :         struct spnego_state *spnego_state = state->spnego;
    2006      272000 :         const struct spnego_neg_ops *ops = NULL;
    2007             :         NTSTATUS status;
    2008             : 
    2009      272000 :         state->sub.in = data_blob_null;
    2010      272000 :         state->sub.needed = false;
    2011             : 
    2012      272000 :         if (spnego_state->state_position == SPNEGO_FALLBACK) {
    2013         432 :                 status = state->sub.status;
    2014         432 :                 spnego_state->out_frag = state->sub.out;
    2015         432 :                 talloc_steal(spnego_state, spnego_state->out_frag.data);
    2016         432 :                 state->sub.out = data_blob_null;
    2017         432 :                 goto respond;
    2018             :         }
    2019             : 
    2020      271568 :         ops = state->n->ops;
    2021             : 
    2022      271568 :         if (GENSEC_UPDATE_IS_NTERROR(state->sub.status)) {
    2023             : 
    2024             : 
    2025             :                 /*
    2026             :                  * gensec_update_recv() returned an error,
    2027             :                  * let's see if the step_fn() want to
    2028             :                  * handle it and negotiate something else.
    2029             :                  */
    2030             : 
    2031        2336 :                 status = ops->step_fn(state->gensec,
    2032             :                                       spnego_state,
    2033             :                                       state->n,
    2034             :                                       state->spnego_in,
    2035             :                                       state->sub.status,
    2036             :                                       state,
    2037             :                                       &state->sub.in);
    2038        2336 :                 if (GENSEC_UPDATE_IS_NTERROR(status)) {
    2039        1922 :                         tevent_req_nterror(req, status);
    2040        1922 :                         return;
    2041             :                 }
    2042             : 
    2043         414 :                 state->sub.out = data_blob_null;
    2044         414 :                 state->sub.status = NT_STATUS_INTERNAL_ERROR;
    2045             : 
    2046         414 :                 if (NT_STATUS_IS_OK(status)) {
    2047             :                         /*
    2048             :                          * Call finish_fn() with an empty
    2049             :                          * blob and NT_STATUS_OK.
    2050             :                          */
    2051           0 :                         state->sub.status = NT_STATUS_OK;
    2052             :                 } else {
    2053             :                         /*
    2054             :                          * MORE_PROCESSING_REQUIRED...
    2055             :                          */
    2056         414 :                         state->sub.needed = true;
    2057             :                 }
    2058             :         }
    2059             : 
    2060      269646 :         if (state->sub.needed) {
    2061         414 :                 struct tevent_req *subreq = NULL;
    2062             : 
    2063             :                 /*
    2064             :                  * We may need one more roundtrip...
    2065             :                  */
    2066         414 :                 subreq = gensec_update_send(state, state->ev,
    2067             :                                             spnego_state->sub_sec_security,
    2068             :                                             state->sub.in);
    2069         414 :                 if (tevent_req_nomem(subreq, req)) {
    2070           0 :                         return;
    2071             :                 }
    2072         414 :                 tevent_req_set_callback(subreq,
    2073             :                                         gensec_spnego_update_done,
    2074             :                                         req);
    2075         414 :                 state->sub.needed = false;
    2076         414 :                 return;
    2077             :         }
    2078             : 
    2079      269232 :         status = ops->finish_fn(state->gensec,
    2080             :                                 spnego_state,
    2081             :                                 state->n,
    2082             :                                 state->spnego_in,
    2083             :                                 state->sub.status,
    2084             :                                 state->sub.out,
    2085             :                                 spnego_state,
    2086             :                                 &spnego_state->out_frag);
    2087      269232 :         TALLOC_FREE(state->n);
    2088      269232 :         if (GENSEC_UPDATE_IS_NTERROR(status)) {
    2089           0 :                 tevent_req_nterror(req, status);
    2090           0 :                 return;
    2091             :         }
    2092             : 
    2093      269232 :         if (NT_STATUS_IS_OK(status)) {
    2094      104632 :                 bool reset_full = true;
    2095             : 
    2096      104632 :                 reset_full = !spnego_state->done_mic_check;
    2097             : 
    2098      104632 :                 status = gensec_may_reset_crypto(spnego_state->sub_sec_security,
    2099             :                                                  reset_full);
    2100      104632 :                 if (tevent_req_nterror(req, status)) {
    2101           0 :                         return;
    2102             :                 }
    2103             :         }
    2104             : 
    2105      269232 : respond:
    2106      269664 :         spnego_state->out_status = status;
    2107             : 
    2108      269664 :         status = gensec_spnego_update_out(state->gensec,
    2109             :                                           state, &state->out);
    2110      269664 :         if (GENSEC_UPDATE_IS_NTERROR(status)) {
    2111           0 :                 tevent_req_nterror(req, status);
    2112           0 :                 return;
    2113             :         }
    2114             : 
    2115      269664 :         state->status = status;
    2116      269664 :         tevent_req_done(req);
    2117      269664 :         return;
    2118             : }
    2119             : 
    2120      270328 : static NTSTATUS gensec_spnego_update_out(struct gensec_security *gensec_security,
    2121             :                                          TALLOC_CTX *out_mem_ctx,
    2122             :                                          DATA_BLOB *_out)
    2123             : {
    2124      270328 :         struct spnego_state *spnego_state =
    2125      270328 :                 talloc_get_type_abort(gensec_security->private_data,
    2126             :                 struct spnego_state);
    2127      270328 :         DATA_BLOB out = data_blob_null;
    2128             :         bool ok;
    2129             : 
    2130      270328 :         *_out = data_blob_null;
    2131             : 
    2132      270328 :         if (spnego_state->out_frag.length <= spnego_state->out_max_length) {
    2133             :                 /*
    2134             :                  * Fast path, we can deliver everything
    2135             :                  */
    2136             : 
    2137      269664 :                 *_out = spnego_state->out_frag;
    2138      269664 :                 if (spnego_state->out_frag.length > 0) {
    2139      217176 :                         talloc_steal(out_mem_ctx, _out->data);
    2140      217176 :                         spnego_state->out_frag = data_blob_null;
    2141             :                 }
    2142             : 
    2143      269664 :                 if (!NT_STATUS_IS_OK(spnego_state->out_status)) {
    2144      164705 :                         return spnego_state->out_status;
    2145             :                 }
    2146             : 
    2147             :                 /*
    2148             :                  * We're completely done, further updates are not allowed.
    2149             :                  */
    2150      104959 :                 spnego_state->state_position = SPNEGO_DONE;
    2151      104959 :                 return gensec_child_ready(gensec_security,
    2152             :                                           spnego_state->sub_sec_security);
    2153             :         }
    2154             : 
    2155         664 :         out = spnego_state->out_frag;
    2156             : 
    2157             :         /*
    2158             :          * copy the remaining bytes
    2159             :          */
    2160         664 :         spnego_state->out_frag = data_blob_talloc(spnego_state,
    2161             :                                         out.data + spnego_state->out_max_length,
    2162             :                                         out.length - spnego_state->out_max_length);
    2163         664 :         if (spnego_state->out_frag.data == NULL) {
    2164           0 :                 return NT_STATUS_NO_MEMORY;
    2165             :         }
    2166             : 
    2167             :         /*
    2168             :          * truncate the buffer
    2169             :          */
    2170         664 :         ok = data_blob_realloc(spnego_state, &out,
    2171             :                                spnego_state->out_max_length);
    2172         664 :         if (!ok) {
    2173           0 :                 return NT_STATUS_NO_MEMORY;
    2174             :         }
    2175             : 
    2176         664 :         talloc_steal(out_mem_ctx, out.data);
    2177         664 :         *_out = out;
    2178         664 :         return NT_STATUS_MORE_PROCESSING_REQUIRED;
    2179             : }
    2180             : 
    2181      272927 : static NTSTATUS gensec_spnego_update_recv(struct tevent_req *req,
    2182             :                                           TALLOC_CTX *out_mem_ctx,
    2183             :                                           DATA_BLOB *out)
    2184             : {
    2185      272927 :         struct gensec_spnego_update_state *state =
    2186      272927 :                 tevent_req_data(req,
    2187             :                 struct gensec_spnego_update_state);
    2188             :         NTSTATUS status;
    2189             : 
    2190      272927 :         *out = data_blob_null;
    2191             : 
    2192      272927 :         if (tevent_req_is_nterror(req, &status)) {
    2193        1935 :                 tevent_req_received(req);
    2194        1935 :                 return status;
    2195             :         }
    2196             : 
    2197      270992 :         *out = state->out;
    2198      270992 :         talloc_steal(out_mem_ctx, state->out.data);
    2199      270992 :         status = state->status;
    2200      270992 :         tevent_req_received(req);
    2201      270992 :         return status;
    2202             : }
    2203             : 
    2204             : static const char *gensec_spnego_oids[] = { 
    2205             :         GENSEC_OID_SPNEGO,
    2206             :         NULL 
    2207             : };
    2208             : 
    2209             : static const struct gensec_security_ops gensec_spnego_security_ops = {
    2210             :         .name             = "spnego",
    2211             :         .sasl_name        = "GSS-SPNEGO",
    2212             :         .auth_type        = DCERPC_AUTH_TYPE_SPNEGO,
    2213             :         .oid              = gensec_spnego_oids,
    2214             :         .client_start     = gensec_spnego_client_start,
    2215             :         .server_start     = gensec_spnego_server_start,
    2216             :         .update_send      = gensec_spnego_update_send,
    2217             :         .update_recv      = gensec_spnego_update_recv,
    2218             :         .seal_packet      = gensec_child_seal_packet,
    2219             :         .sign_packet      = gensec_child_sign_packet,
    2220             :         .sig_size         = gensec_child_sig_size,
    2221             :         .max_wrapped_size = gensec_child_max_wrapped_size,
    2222             :         .max_input_size   = gensec_child_max_input_size,
    2223             :         .check_packet     = gensec_child_check_packet,
    2224             :         .unseal_packet    = gensec_child_unseal_packet,
    2225             :         .wrap             = gensec_child_wrap,
    2226             :         .unwrap           = gensec_child_unwrap,
    2227             :         .session_key      = gensec_child_session_key,
    2228             :         .session_info     = gensec_child_session_info,
    2229             :         .want_feature     = gensec_child_want_feature,
    2230             :         .have_feature     = gensec_child_have_feature,
    2231             :         .expire_time      = gensec_child_expire_time,
    2232             :         .final_auth_type  = gensec_child_final_auth_type,
    2233             :         .enabled          = true,
    2234             :         .priority         = GENSEC_SPNEGO,
    2235             :         .glue             = true,
    2236             : };
    2237             : 
    2238       37127 : _PUBLIC_ NTSTATUS gensec_spnego_init(TALLOC_CTX *ctx)
    2239             : {
    2240             :         NTSTATUS ret;
    2241       37127 :         ret = gensec_register(ctx, &gensec_spnego_security_ops);
    2242       37127 :         if (!NT_STATUS_IS_OK(ret)) {
    2243           0 :                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
    2244             :                         gensec_spnego_security_ops.name));
    2245           0 :                 return ret;
    2246             :         }
    2247             : 
    2248       37127 :         return ret;
    2249             : }

Generated by: LCOV version 1.13