LCOV - code coverage report
Current view: top level - auth/gensec - spnego.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 766 898 85.3 %
Date: 2024-05-31 13:13:24 Functions: 30 30 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 packet 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      341727 : static struct spnego_neg_state *gensec_spnego_neg_state(TALLOC_CTX *mem_ctx,
     153             :                 const struct spnego_neg_ops *ops)
     154             : {
     155      341727 :         struct spnego_neg_state *n = NULL;
     156             : 
     157      346995 :         n = talloc_zero(mem_ctx, struct spnego_neg_state);
     158      341727 :         if (n == NULL) {
     159           0 :                 return NULL;
     160             :         }
     161      341727 :         n->ops = ops;
     162             : 
     163      341727 :         return n;
     164             : }
     165             : 
     166       25740 : static void gensec_spnego_reset_sub_sec(struct spnego_state *spnego_state)
     167             : {
     168       25740 :         spnego_state->sub_sec_ready = false;
     169       25740 :         TALLOC_FREE(spnego_state->sub_sec_security);
     170       25734 : }
     171             : 
     172       71586 : static NTSTATUS gensec_spnego_client_start(struct gensec_security *gensec_security)
     173             : {
     174        1355 :         struct spnego_state *spnego_state;
     175             : 
     176       71586 :         spnego_state = talloc_zero(gensec_security, struct spnego_state);
     177       71586 :         if (!spnego_state) {
     178           0 :                 return NT_STATUS_NO_MEMORY;
     179             :         }
     180             : 
     181       71586 :         spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT;
     182       71586 :         spnego_state->state_position = SPNEGO_CLIENT_START;
     183       71586 :         spnego_state->sub_sec_security = NULL;
     184       71586 :         spnego_state->sub_sec_ready = false;
     185       71586 :         spnego_state->mech_types = data_blob_null;
     186       71586 :         spnego_state->out_max_length = gensec_max_update_size(gensec_security);
     187       71586 :         spnego_state->out_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
     188             : 
     189       71586 :         spnego_state->simulate_w2k = gensec_setting_bool(gensec_security->settings,
     190             :                                                 "spnego", "simulate_w2k", false);
     191       71586 :         spnego_state->no_optimistic = gensec_setting_bool(gensec_security->settings,
     192             :                                                           "spnego",
     193             :                                                           "client_no_optimistic",
     194             :                                                           false);
     195             : 
     196       71586 :         gensec_security->private_data = spnego_state;
     197       71586 :         return NT_STATUS_OK;
     198             : }
     199             : 
     200      121316 : static NTSTATUS gensec_spnego_server_start(struct gensec_security *gensec_security)
     201             : {
     202        2349 :         struct spnego_state *spnego_state;
     203             : 
     204      121316 :         spnego_state = talloc_zero(gensec_security, struct spnego_state);
     205      121316 :         if (!spnego_state) {
     206           0 :                 return NT_STATUS_NO_MEMORY;
     207             :         }
     208             : 
     209      121316 :         spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT;
     210      121316 :         spnego_state->state_position = SPNEGO_SERVER_START;
     211      121316 :         spnego_state->sub_sec_security = NULL;
     212      121316 :         spnego_state->sub_sec_ready = false;
     213      121316 :         spnego_state->mech_types = data_blob_null;
     214      121316 :         spnego_state->out_max_length = gensec_max_update_size(gensec_security);
     215      121316 :         spnego_state->out_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
     216             : 
     217      121316 :         spnego_state->simulate_w2k = gensec_setting_bool(gensec_security->settings,
     218             :                                                 "spnego", "simulate_w2k", false);
     219             : 
     220      121316 :         gensec_security->private_data = spnego_state;
     221      121316 :         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         170 : 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           0 :         int i,j;
     237           0 :         const struct gensec_security_ops **all_ops;
     238             : 
     239         170 :         all_ops = gensec_security_mechs(gensec_security, mem_ctx);
     240             : 
     241         368 :         for (i=0; all_ops && all_ops[i]; i++) {
     242           0 :                 bool is_spnego;
     243           0 :                 NTSTATUS nt_status;
     244             : 
     245         368 :                 if (gensec_security != NULL &&
     246         368 :                     !gensec_security_ops_enabled(all_ops[i], gensec_security))
     247             :                 {
     248         198 :                         continue;
     249             :                 }
     250             : 
     251         314 :                 if (!all_ops[i]->oid) {
     252          78 :                         continue;
     253             :                 }
     254             : 
     255         236 :                 is_spnego = false;
     256         578 :                 for (j=0; all_ops[i]->oid[j]; j++) {
     257         342 :                         if (strcasecmp(GENSEC_OID_SPNEGO,all_ops[i]->oid[j]) == 0) {
     258          28 :                                 is_spnego = true;
     259             :                         }
     260             :                 }
     261         236 :                 if (is_spnego) {
     262          28 :                         continue;
     263             :                 }
     264             : 
     265         208 :                 if (!all_ops[i]->magic) {
     266           0 :                         continue;
     267             :                 }
     268             : 
     269         208 :                 nt_status = all_ops[i]->magic(gensec_security, &in);
     270         208 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     271          38 :                         continue;
     272             :                 }
     273             : 
     274         170 :                 spnego_state->state_position = SPNEGO_FALLBACK;
     275             : 
     276         170 :                 nt_status = gensec_subcontext_start(spnego_state, 
     277             :                                                     gensec_security, 
     278             :                                                     &spnego_state->sub_sec_security);
     279             : 
     280         170 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     281         170 :                         return nt_status;
     282             :                 }
     283             :                 /* select the sub context */
     284         170 :                 nt_status = gensec_start_mech_by_ops(spnego_state->sub_sec_security,
     285         170 :                                                      all_ops[i]);
     286         170 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     287           0 :                         return nt_status;
     288             :                 }
     289             : 
     290         170 :                 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       84369 : 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       84369 :         n->mech_idx = 0;
     305       84369 :         n->mech_types = gensec_security_oids(gensec_security, n,
     306             :                                              GENSEC_OID_SPNEGO);
     307       84369 :         if (n->mech_types == NULL) {
     308           0 :                 DBG_WARNING("gensec_security_oids() failed\n");
     309           0 :                 return NT_STATUS_NO_MEMORY;
     310             :         }
     311             : 
     312       84369 :         n->all_idx = 0;
     313       84369 :         n->all_sec = gensec_security_by_oid_list(gensec_security,
     314             :                                                  n, n->mech_types,
     315             :                                                  GENSEC_OID_SPNEGO);
     316       84369 :         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       84369 :         return n->ops->step_fn(gensec_security, spnego_state, n,
     322       84369 :                                spnego_in, NT_STATUS_OK, in_mem_ctx, in_next);
     323             : }
     324             : 
     325       84586 : 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       84586 :         if (!NT_STATUS_IS_OK(last_status)) {
     335         217 :                 const struct gensec_security_ops_wrapper *cur_sec =
     336         217 :                         &n->all_sec[n->all_idx];
     337         217 :                 const struct gensec_security_ops_wrapper *next_sec = NULL;
     338         217 :                 const char *next = NULL;
     339         217 :                 const char *principal = NULL;
     340         217 :                 int dbg_level = DBGLVL_WARNING;
     341         217 :                 NTSTATUS status = last_status;
     342             : 
     343         217 :                 if (cur_sec[1].op != NULL) {
     344          33 :                         next_sec = &cur_sec[1];
     345             :                 }
     346             : 
     347         217 :                 if (next_sec != NULL) {
     348          33 :                         next = next_sec->op->name;
     349          33 :                         dbg_level = DBGLVL_NOTICE;
     350             :                 }
     351             : 
     352         217 :                 if (gensec_security->target.principal != NULL) {
     353           0 :                         principal = gensec_security->target.principal;
     354         217 :                 } else if (gensec_security->target.service != NULL &&
     355         217 :                            gensec_security->target.hostname != NULL)
     356             :                 {
     357         217 :                         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         217 :                 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         217 :                 if (next == NULL) {
     371             :                         /*
     372             :                          * A hard error without a possible fallback.
     373             :                          */
     374         184 :                         return status;
     375             :                 }
     376             : 
     377             :                 /*
     378             :                  * Pretend we never started it
     379             :                  */
     380          33 :                 gensec_spnego_reset_sub_sec(spnego_state);
     381             : 
     382             :                 /*
     383             :                  * And try the next one...
     384             :                  */
     385          33 :                 n->all_idx += 1;
     386             :         }
     387             : 
     388       86043 :         for (; n->all_sec[n->all_idx].op != NULL; n->all_idx++) {
     389       86042 :                 const struct gensec_security_ops_wrapper *cur_sec =
     390       84522 :                         &n->all_sec[n->all_idx];
     391        1520 :                 NTSTATUS status;
     392             : 
     393       86042 :                 status = gensec_subcontext_start(spnego_state,
     394             :                                                  gensec_security,
     395             :                                                  &spnego_state->sub_sec_security);
     396       86042 :                 if (!NT_STATUS_IS_OK(status)) {
     397       82881 :                         return status;
     398             :                 }
     399             : 
     400             :                 /* select the sub context */
     401       87562 :                 status = gensec_start_mech_by_ops(spnego_state->sub_sec_security,
     402       86042 :                                                   cur_sec->op);
     403       86042 :                 if (!NT_STATUS_IS_OK(status)) {
     404        1641 :                         gensec_spnego_reset_sub_sec(spnego_state);
     405        1641 :                         continue;
     406             :                 }
     407             : 
     408             :                 /* In the client, try and produce the first (optimistic) packet */
     409       84401 :                 if (spnego_state->state_position == SPNEGO_CLIENT_START) {
     410       32856 :                         *in_next = data_blob_null;
     411       32856 :                         return NT_STATUS_MORE_PROCESSING_REQUIRED;
     412             :                 }
     413             : 
     414       51545 :                 *in_next = data_blob_null;
     415       51545 :                 return NT_STATUS_OK;
     416             :         }
     417             : 
     418           1 :         DBG_WARNING("Failed to setup SPNEGO negTokenInit request\n");
     419           1 :         return NT_STATUS_INVALID_PARAMETER;
     420             : }
     421             : 
     422       84184 : 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       84184 :         const struct gensec_security_ops_wrapper *cur_sec =
     433       84184 :                         &n->all_sec[n->all_idx];
     434        1520 :         struct spnego_data spnego_out;
     435        1520 :         bool ok;
     436             : 
     437       84184 :         spnego_out.type = SPNEGO_NEG_TOKEN_INIT;
     438             : 
     439       84184 :         n->mech_types = gensec_security_oids_from_ops_wrapped(n, cur_sec);
     440       84184 :         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       84184 :         ok = spnego_write_mech_types(spnego_state,
     446             :                                      n->mech_types,
     447             :                                      &spnego_state->mech_types);
     448       84184 :         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       84184 :         spnego_out.negTokenInit.mechTypes = n->mech_types;
     455       84184 :         spnego_out.negTokenInit.reqFlags = data_blob_null;
     456       84184 :         spnego_out.negTokenInit.reqFlagsPadding = 0;
     457             : 
     458       84184 :         if (spnego_state->state_position == SPNEGO_SERVER_START) {
     459        1296 :                 spnego_out.negTokenInit.mechListMIC
     460       51545 :                         = data_blob_string_const(ADS_IGNORE_PRINCIPAL);
     461             :         } else {
     462       32639 :                 spnego_out.negTokenInit.mechListMIC = data_blob_null;
     463             :         }
     464             : 
     465       84184 :         spnego_out.negTokenInit.mechToken = sub_out;
     466             : 
     467       84184 :         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       84184 :         spnego_state->neg_oid = cur_sec->oid;
     478             : 
     479             :         /* set next state */
     480       84184 :         if (spnego_state->state_position == SPNEGO_SERVER_START) {
     481       51545 :                 spnego_state->state_position = SPNEGO_SERVER_START;
     482       51545 :                 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT;
     483             :         } else {
     484       32639 :                 spnego_state->state_position = SPNEGO_CLIENT_TARG;
     485       32639 :                 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
     486             :         }
     487             : 
     488       84184 :         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       38760 : 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             :         /* The server offers a list of mechanisms */
     507             : 
     508       38760 :         n->mech_idx = 0;
     509             : 
     510             :         /* Do not use server mech list as it isn't protected. Instead, get all
     511             :          * supported mechs (excluding SPNEGO). */
     512       38760 :         n->mech_types = gensec_security_oids(gensec_security, n,
     513             :                                              GENSEC_OID_SPNEGO);
     514       38760 :         if (n->mech_types == NULL) {
     515           0 :                 return NT_STATUS_INVALID_PARAMETER;
     516             :         }
     517             : 
     518       38760 :         n->all_idx = 0;
     519       38760 :         n->all_sec = gensec_security_by_oid_list(gensec_security,
     520             :                                                  n, n->mech_types,
     521             :                                                  GENSEC_OID_SPNEGO);
     522       38760 :         if (n->all_sec == NULL) {
     523           0 :                 DBG_WARNING("gensec_security_by_oid_list() failed\n");
     524           0 :                 return NT_STATUS_INVALID_PARAMETER;
     525             :         }
     526             : 
     527       38760 :         return n->ops->step_fn(gensec_security, spnego_state, n,
     528       38760 :                                spnego_in, NT_STATUS_OK, in_mem_ctx, in_next);
     529             : }
     530             : 
     531       39980 : static NTSTATUS gensec_spnego_client_negTokenInit_step(
     532             :                                         struct gensec_security *gensec_security,
     533             :                                         struct spnego_state *spnego_state,
     534             :                                         struct spnego_neg_state *n,
     535             :                                         struct spnego_data *spnego_in,
     536             :                                         NTSTATUS last_status,
     537             :                                         TALLOC_CTX *in_mem_ctx,
     538             :                                         DATA_BLOB *in_next)
     539             : {
     540       39980 :         if (!NT_STATUS_IS_OK(last_status)) {
     541        1220 :                 const struct gensec_security_ops_wrapper *cur_sec =
     542        1220 :                         &n->all_sec[n->all_idx];
     543        1220 :                 const struct gensec_security_ops_wrapper *next_sec = NULL;
     544        1220 :                 const char *next = NULL;
     545        1220 :                 const char *principal = NULL;
     546        1220 :                 int dbg_level = DBGLVL_WARNING;
     547        1220 :                 bool allow_fallback = false;
     548        1220 :                 NTSTATUS status = last_status;
     549             : 
     550        1220 :                 if (cur_sec[1].op != NULL) {
     551        1206 :                         next_sec = &cur_sec[1];
     552             :                 }
     553             : 
     554             :                 /*
     555             :                  * it is likely that a NULL input token will
     556             :                  * not be liked by most server mechs, but if
     557             :                  * we are in the client, we want the first
     558             :                  * update packet to be able to abort the use
     559             :                  * of this mech
     560             :                  */
     561        1220 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
     562        1216 :                     NT_STATUS_EQUAL(status, NT_STATUS_INVALID_ACCOUNT_NAME) ||
     563        1216 :                     NT_STATUS_EQUAL(status, NT_STATUS_INVALID_COMPUTER_NAME) ||
     564        1216 :                     NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN) ||
     565        1216 :                     NT_STATUS_EQUAL(status, NT_STATUS_NO_LOGON_SERVERS) ||
     566          22 :                     NT_STATUS_EQUAL(status, NT_STATUS_TIME_DIFFERENCE_AT_DC) ||
     567          22 :                     NT_STATUS_EQUAL(status, NT_STATUS_CANT_ACCESS_DOMAIN_INFO))
     568             :                 {
     569        1198 :                         allow_fallback = true;
     570             :                 }
     571             : 
     572        1220 :                 if (allow_fallback && next_sec != NULL) {
     573        1196 :                         next = next_sec->op->name;
     574        1196 :                         dbg_level = DBGLVL_NOTICE;
     575             :                 }
     576             : 
     577        1220 :                 if (gensec_security->target.principal != NULL) {
     578           0 :                         principal = gensec_security->target.principal;
     579        1220 :                 } else if (gensec_security->target.service != NULL &&
     580        1220 :                            gensec_security->target.hostname != NULL)
     581             :                 {
     582        1220 :                         principal = talloc_asprintf(spnego_state->sub_sec_security,
     583             :                                                     "%s/%s",
     584             :                                                     gensec_security->target.service,
     585             :                                                     gensec_security->target.hostname);
     586             :                 } else {
     587           0 :                         principal = gensec_security->target.hostname;
     588             :                 }
     589             : 
     590        1220 :                 DBG_PREFIX(dbg_level, (
     591             :                            "%s: creating NEG_TOKEN_INIT for %s failed "
     592             :                            "(next[%s]): %s\n", cur_sec->op->name,
     593             :                            principal, next, nt_errstr(status)));
     594             : 
     595        1220 :                 if (next == NULL) {
     596             :                         /*
     597             :                          * A hard error without a possible fallback.
     598             :                          */
     599          24 :                         return status;
     600             :                 }
     601             : 
     602             :                 /*
     603             :                  * Pretend we never started it.
     604             :                  */
     605        1196 :                 gensec_spnego_reset_sub_sec(spnego_state);
     606             : 
     607             :                 /*
     608             :                  * And try the next one...
     609             :                  */
     610        1196 :                 n->all_idx += 1;
     611             :         }
     612             : 
     613       62824 :         for (; n->all_sec[n->all_idx].op != NULL; n->all_idx++) {
     614       62807 :                 const struct gensec_security_ops_wrapper *cur_sec =
     615       61670 :                         &n->all_sec[n->all_idx];
     616        1137 :                 NTSTATUS status;
     617             : 
     618       62807 :                 status = gensec_subcontext_start(spnego_state,
     619             :                                                  gensec_security,
     620             :                                                  &spnego_state->sub_sec_security);
     621       62807 :                 if (!NT_STATUS_IS_OK(status)) {
     622       38808 :                         return status;
     623             :                 }
     624             : 
     625             :                 /* select the sub context */
     626       63944 :                 status = gensec_start_mech_by_ops(spnego_state->sub_sec_security,
     627       62807 :                                                   cur_sec->op);
     628       62807 :                 if (!NT_STATUS_IS_OK(status)) {
     629       22868 :                         gensec_spnego_reset_sub_sec(spnego_state);
     630       22868 :                         continue;
     631             :                 }
     632             : 
     633             :                 /*
     634             :                  * Note that 'cur_sec' is temporary memory, but
     635             :                  * cur_sec->oid points to a const string in the
     636             :                  * backends gensec_security_ops structure.
     637             :                  */
     638       39939 :                 spnego_state->neg_oid = cur_sec->oid;
     639             : 
     640             :                 /*
     641             :                  * As client we don't use an optimistic token from the server.
     642             :                  * But try to produce one for the server.
     643             :                  */
     644       39939 :                 *in_next = data_blob_null;
     645       39939 :                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
     646             :         }
     647             : 
     648          17 :         DBG_WARNING("Could not find a suitable mechtype in NEG_TOKEN_INIT\n");
     649          17 :         return NT_STATUS_INVALID_PARAMETER;
     650             : }
     651             : 
     652       38719 : static NTSTATUS gensec_spnego_client_negTokenInit_finish(
     653             :                                         struct gensec_security *gensec_security,
     654             :                                         struct spnego_state *spnego_state,
     655             :                                         struct spnego_neg_state *n,
     656             :                                         struct spnego_data *spnego_in,
     657             :                                         NTSTATUS sub_status,
     658             :                                         const DATA_BLOB sub_out,
     659             :                                         TALLOC_CTX *out_mem_ctx,
     660             :                                         DATA_BLOB *out)
     661             : {
     662        1131 :         struct spnego_data spnego_out;
     663       38719 :         const char * const *mech_types = NULL;
     664        1131 :         bool ok;
     665             : 
     666       38719 :         if (n->mech_types == NULL) {
     667           0 :                 DBG_WARNING("No mech_types list\n");
     668           0 :                 return NT_STATUS_INVALID_PARAMETER;
     669             :         }
     670             : 
     671       86815 :         for (mech_types = n->mech_types; *mech_types != NULL; mech_types++) {
     672       86815 :                 int cmp = strcmp(*mech_types, spnego_state->neg_oid);
     673             : 
     674       86815 :                 if (cmp == 0) {
     675       37588 :                         break;
     676             :                 }
     677             :         }
     678             : 
     679       38719 :         if (*mech_types == NULL) {
     680           0 :                 DBG_ERR("Can't find selected sub mechanism in mech_types\n");
     681           0 :                 return NT_STATUS_INVALID_PARAMETER;
     682             :         }
     683             : 
     684             :         /* compose reply */
     685       38719 :         spnego_out.type = SPNEGO_NEG_TOKEN_INIT;
     686       38719 :         spnego_out.negTokenInit.mechTypes = mech_types;
     687       38719 :         spnego_out.negTokenInit.reqFlags = data_blob_null;
     688       38719 :         spnego_out.negTokenInit.reqFlagsPadding = 0;
     689       38719 :         spnego_out.negTokenInit.mechListMIC = data_blob_null;
     690       38719 :         spnego_out.negTokenInit.mechToken = sub_out;
     691             : 
     692       38719 :         if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
     693           0 :                 DBG_ERR("Failed to write SPNEGO reply to NEG_TOKEN_INIT\n");
     694           0 :                 return NT_STATUS_INVALID_PARAMETER;
     695             :         }
     696             : 
     697       38719 :         ok = spnego_write_mech_types(spnego_state,
     698             :                                      mech_types,
     699             :                                      &spnego_state->mech_types);
     700       38719 :         if (!ok) {
     701           0 :                 DBG_ERR("failed to write mechTypes\n");
     702           0 :                 return NT_STATUS_NO_MEMORY;
     703             :         }
     704             : 
     705             :         /* set next state */
     706       38719 :         spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
     707       38719 :         spnego_state->state_position = SPNEGO_CLIENT_TARG;
     708             : 
     709       38719 :         return NT_STATUS_MORE_PROCESSING_REQUIRED;
     710             : }
     711             : 
     712             : static const struct spnego_neg_ops gensec_spnego_client_negTokenInit_ops = {
     713             :         .name      = "client_negTokenInit",
     714             :         .start_fn  = gensec_spnego_client_negTokenInit_start,
     715             :         .step_fn   = gensec_spnego_client_negTokenInit_step,
     716             :         .finish_fn = gensec_spnego_client_negTokenInit_finish,
     717             : };
     718             : 
     719      107253 : static NTSTATUS gensec_spnego_client_negTokenTarg_start(
     720             :                                         struct gensec_security *gensec_security,
     721             :                                         struct spnego_state *spnego_state,
     722             :                                         struct spnego_neg_state *n,
     723             :                                         struct spnego_data *spnego_in,
     724             :                                         TALLOC_CTX *in_mem_ctx,
     725             :                                         DATA_BLOB *in_next)
     726             : {
     727      107253 :         struct spnego_negTokenTarg *ta = &spnego_in->negTokenTarg;
     728        1303 :         NTSTATUS status;
     729             : 
     730      107253 :         spnego_state->num_targs++;
     731             : 
     732      107253 :         if (ta->negResult == SPNEGO_REJECT) {
     733           0 :                 return NT_STATUS_LOGON_FAILURE;
     734             :         }
     735             : 
     736      107253 :         if (ta->negResult == SPNEGO_REQUEST_MIC) {
     737           2 :                 spnego_state->mic_requested = true;
     738             :         }
     739             : 
     740      107253 :         if (ta->mechListMIC.length > 0) {
     741       38306 :                 DATA_BLOB *m = &ta->mechListMIC;
     742       38306 :                 const DATA_BLOB *r = &ta->responseToken;
     743             : 
     744             :                 /*
     745             :                  * Windows 2000 has a bug, it repeats the
     746             :                  * responseToken in the mechListMIC field.
     747             :                  */
     748       38306 :                 if (m->length == r->length) {
     749           0 :                         int cmp;
     750             : 
     751        3314 :                         cmp = memcmp(m->data, r->data, m->length);
     752        3314 :                         if (cmp == 0) {
     753        3314 :                                 data_blob_free(m);
     754             :                         }
     755             :                 }
     756             :         }
     757             : 
     758             :         /* Server didn't like our choice of mech, and chose something else */
     759      107253 :         if (((ta->negResult == SPNEGO_ACCEPT_INCOMPLETE) ||
     760       64533 :              (ta->negResult == SPNEGO_REQUEST_MIC)) &&
     761       41941 :             ta->supportedMech != NULL &&
     762       41941 :             strcmp(ta->supportedMech, spnego_state->neg_oid) != 0)
     763             :         {
     764           2 :                 const char *client_mech = NULL;
     765           2 :                 const char *client_oid = NULL;
     766           2 :                 const char *server_mech = NULL;
     767           2 :                 const char *server_oid = NULL;
     768             : 
     769           2 :                 client_mech = gensec_get_name_by_oid(gensec_security,
     770             :                                                      spnego_state->neg_oid);
     771           2 :                 client_oid = spnego_state->neg_oid;
     772           2 :                 server_mech = gensec_get_name_by_oid(gensec_security,
     773             :                                                      ta->supportedMech);
     774           2 :                 server_oid = ta->supportedMech;
     775             : 
     776           2 :                 DBG_NOTICE("client preferred mech (%s[%s]) not accepted, "
     777             :                            "server wants: %s[%s]\n",
     778             :                            client_mech, client_oid, server_mech, server_oid);
     779             : 
     780           2 :                 spnego_state->downgraded = true;
     781           2 :                 gensec_spnego_reset_sub_sec(spnego_state);
     782             : 
     783           2 :                 status = gensec_subcontext_start(spnego_state,
     784             :                                                  gensec_security,
     785             :                                                  &spnego_state->sub_sec_security);
     786           2 :                 if (!NT_STATUS_IS_OK(status)) {
     787           0 :                         return status;
     788             :                 }
     789             : 
     790             :                 /* select the sub context */
     791           2 :                 status = gensec_start_mech_by_oid(spnego_state->sub_sec_security,
     792             :                                                   ta->supportedMech);
     793           2 :                 if (!NT_STATUS_IS_OK(status)) {
     794           0 :                         return status;
     795             :                 }
     796             : 
     797           2 :                 spnego_state->neg_oid = talloc_strdup(spnego_state,
     798             :                                         ta->supportedMech);
     799           2 :                 if (spnego_state->neg_oid == NULL) {
     800           0 :                         return NT_STATUS_NO_MEMORY;
     801             :                 }
     802             :         }
     803             : 
     804      107253 :         if (ta->mechListMIC.length > 0) {
     805       34992 :                 if (spnego_state->sub_sec_ready) {
     806       34988 :                         spnego_state->needs_mic_check = true;
     807             :                 }
     808             :         }
     809             : 
     810      107253 :         if (spnego_state->needs_mic_check) {
     811       34992 :                 if (ta->responseToken.length != 0) {
     812           0 :                         DBG_WARNING("non empty response token not expected\n");
     813           0 :                         return NT_STATUS_INVALID_PARAMETER;
     814             :                 }
     815             : 
     816       34992 :                 if (ta->mechListMIC.length == 0
     817           4 :                     && spnego_state->may_skip_mic_check) {
     818             :                         /*
     819             :                          * In this case we don't require
     820             :                          * a mechListMIC from the server.
     821             :                          *
     822             :                          * This works around bugs in the Azure
     823             :                          * and Apple spnego implementations.
     824             :                          *
     825             :                          * See
     826             :                          * https://bugzilla.samba.org/show_bug.cgi?id=11994
     827             :                          */
     828           2 :                         spnego_state->needs_mic_check = false;
     829           2 :                         return NT_STATUS_OK;
     830             :                 }
     831             : 
     832       35221 :                 status = gensec_check_packet(spnego_state->sub_sec_security,
     833       34759 :                                              spnego_state->mech_types.data,
     834             :                                              spnego_state->mech_types.length,
     835       34990 :                                              spnego_state->mech_types.data,
     836             :                                              spnego_state->mech_types.length,
     837       34990 :                                              &ta->mechListMIC);
     838       34990 :                 if (!NT_STATUS_IS_OK(status)) {
     839           2 :                         DBG_WARNING("failed to verify mechListMIC: %s\n",
     840             :                                     nt_errstr(status));
     841           2 :                         return status;
     842             :                 }
     843       34988 :                 spnego_state->needs_mic_check = false;
     844       34988 :                 spnego_state->done_mic_check = true;
     845       34988 :                 return NT_STATUS_OK;
     846             :         }
     847             : 
     848       72261 :         if (!spnego_state->sub_sec_ready) {
     849       69303 :                 *in_next = ta->responseToken;
     850       69303 :                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
     851             :         }
     852             : 
     853        2958 :         return NT_STATUS_OK;
     854             : }
     855             : 
     856          97 : static NTSTATUS gensec_spnego_client_negTokenTarg_step(
     857             :                                         struct gensec_security *gensec_security,
     858             :                                         struct spnego_state *spnego_state,
     859             :                                         struct spnego_neg_state *n,
     860             :                                         struct spnego_data *spnego_in,
     861             :                                         NTSTATUS last_status,
     862             :                                         TALLOC_CTX *in_mem_ctx,
     863             :                                         DATA_BLOB *in_next)
     864             : {
     865          97 :         if (GENSEC_UPDATE_IS_NTERROR(last_status)) {
     866          97 :                 DBG_WARNING("SPNEGO(%s) login failed: %s\n",
     867             :                             spnego_state->sub_sec_security->ops->name,
     868             :                             nt_errstr(last_status));
     869          97 :                 return last_status;
     870             :         }
     871             : 
     872             :         /*
     873             :          * This should never be reached!
     874             :          * The step function is only called on errors!
     875             :          */
     876           0 :         smb_panic(__location__);
     877             :         return NT_STATUS_INTERNAL_ERROR;
     878             : }
     879             : 
     880      107154 : static NTSTATUS gensec_spnego_client_negTokenTarg_finish(
     881             :                                         struct gensec_security *gensec_security,
     882             :                                         struct spnego_state *spnego_state,
     883             :                                         struct spnego_neg_state *n,
     884             :                                         struct spnego_data *spnego_in,
     885             :                                         NTSTATUS sub_status,
     886             :                                         const DATA_BLOB sub_out,
     887             :                                         TALLOC_CTX *out_mem_ctx,
     888             :                                         DATA_BLOB *out)
     889             : {
     890      107154 :         const struct spnego_negTokenTarg *ta =
     891             :                 &spnego_in->negTokenTarg;
     892      107154 :         DATA_BLOB mech_list_mic = data_blob_null;
     893        1303 :         NTSTATUS status;
     894        1303 :         struct spnego_data spnego_out;
     895             : 
     896      107154 :         if (!spnego_state->sub_sec_ready) {
     897             :                 /*
     898             :                  * We're not yet ready to deal with signatures.
     899             :                  */
     900           8 :                 goto client_response;
     901             :         }
     902             : 
     903      107146 :         if (spnego_state->done_mic_check) {
     904             :                 /*
     905             :                  * We already checked the mic,
     906             :                  * either the in last round here
     907             :                  * in gensec_spnego_client_negTokenTarg_finish()
     908             :                  * or during this round in
     909             :                  * gensec_spnego_client_negTokenTarg_start().
     910             :                  *
     911             :                  * Both cases we're sure we don't have to
     912             :                  * call gensec_sign_packet().
     913             :                  */
     914       34992 :                 goto client_response;
     915             :         }
     916             : 
     917       72154 :         if (spnego_state->may_skip_mic_check) {
     918             :                 /*
     919             :                  * This can only be set during
     920             :                  * the last round here in
     921             :                  * gensec_spnego_client_negTokenTarg_finish()
     922             :                  * below. And during this round
     923             :                  * we already passed the checks in
     924             :                  * gensec_spnego_client_negTokenTarg_start().
     925             :                  *
     926             :                  * So we need to skip to deal with
     927             :                  * any signatures now.
     928             :                  */
     929        1229 :                 goto client_response;
     930             :         }
     931             : 
     932       70925 :         if (!spnego_state->done_mic_check) {
     933       70925 :                 bool have_sign = true;
     934       70925 :                 bool new_spnego = false;
     935             : 
     936       70925 :                 have_sign = gensec_have_feature(spnego_state->sub_sec_security,
     937             :                                                 GENSEC_FEATURE_SIGN);
     938       70925 :                 if (spnego_state->simulate_w2k) {
     939         293 :                         have_sign = false;
     940             :                 }
     941       70925 :                 new_spnego = gensec_have_feature(spnego_state->sub_sec_security,
     942             :                                                  GENSEC_FEATURE_NEW_SPNEGO);
     943             : 
     944       70925 :                 switch (ta->negResult) {
     945       29089 :                 case SPNEGO_ACCEPT_COMPLETED:
     946             :                 case SPNEGO_NONE_RESULT:
     947       29089 :                         if (spnego_state->num_targs == 1) {
     948             :                                 /*
     949             :                                  * the first exchange doesn't require
     950             :                                  * verification
     951             :                                  */
     952       27492 :                                 new_spnego = false;
     953             :                         }
     954             : 
     955       28298 :                         break;
     956             : 
     957       41836 :                 case SPNEGO_ACCEPT_INCOMPLETE:
     958       41836 :                         if (ta->mechListMIC.length > 0) {
     959           4 :                                 new_spnego = true;
     960           4 :                                 break;
     961             :                         }
     962             : 
     963       41832 :                         if (spnego_state->downgraded) {
     964             :                                 /*
     965             :                                  * A downgrade should be protected if
     966             :                                  * supported
     967             :                                  */
     968           2 :                                 break;
     969             :                         }
     970             : 
     971             :                         /*
     972             :                          * The caller may just asked for
     973             :                          * GENSEC_FEATURE_SESSION_KEY, this
     974             :                          * is only reflected in the want_features.
     975             :                          *
     976             :                          * As it will imply
     977             :                          * gensec_have_features(GENSEC_FEATURE_SIGN)
     978             :                          * to return true.
     979             :                          */
     980       41830 :                         if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
     981       16126 :                                 break;
     982             :                         }
     983       25608 :                         if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
     984         334 :                                 break;
     985             :                         }
     986             :                         /*
     987             :                          * Here we're sure our preferred mech was
     988             :                          * selected by the server and our caller doesn't
     989             :                          * need GENSEC_FEATURE_SIGN nor
     990             :                          * GENSEC_FEATURE_SEAL support.
     991             :                          *
     992             :                          * In this case we don't require
     993             :                          * a mechListMIC from the server.
     994             :                          *
     995             :                          * This works around bugs in the Azure
     996             :                          * and Apple spnego implementations.
     997             :                          *
     998             :                          * See
     999             :                          * https://bugzilla.samba.org/show_bug.cgi?id=11994
    1000             :                          */
    1001       25274 :                         spnego_state->may_skip_mic_check = true;
    1002       25274 :                         break;
    1003             : 
    1004           0 :                 case SPNEGO_REQUEST_MIC:
    1005           0 :                         if (ta->mechListMIC.length > 0) {
    1006           0 :                                 new_spnego = true;
    1007             :                         }
    1008           0 :                         break;
    1009           0 :                 default:
    1010           0 :                         break;
    1011             :                 }
    1012             : 
    1013       70925 :                 if (spnego_state->mic_requested) {
    1014           2 :                         if (have_sign) {
    1015           2 :                                 new_spnego = true;
    1016             :                         }
    1017             :                 }
    1018             : 
    1019       70925 :                 if (have_sign && new_spnego) {
    1020       38871 :                         spnego_state->needs_mic_check = true;
    1021       38871 :                         spnego_state->needs_mic_sign = true;
    1022             :                 }
    1023             :         }
    1024             : 
    1025       70925 :         if (ta->mechListMIC.length > 0) {
    1026           4 :                 status = gensec_check_packet(spnego_state->sub_sec_security,
    1027           4 :                                              spnego_state->mech_types.data,
    1028             :                                              spnego_state->mech_types.length,
    1029           4 :                                              spnego_state->mech_types.data,
    1030             :                                              spnego_state->mech_types.length,
    1031             :                                              &ta->mechListMIC);
    1032           4 :                 if (!NT_STATUS_IS_OK(status)) {
    1033           0 :                         DBG_WARNING("failed to verify mechListMIC: %s\n",
    1034             :                                     nt_errstr(status));
    1035           0 :                         return status;
    1036             :                 }
    1037           4 :                 spnego_state->needs_mic_check = false;
    1038           4 :                 spnego_state->done_mic_check = true;
    1039             :         }
    1040             : 
    1041       70925 :         if (spnego_state->needs_mic_sign) {
    1042       39112 :                 status = gensec_sign_packet(spnego_state->sub_sec_security,
    1043             :                                             n,
    1044       38630 :                                             spnego_state->mech_types.data,
    1045             :                                             spnego_state->mech_types.length,
    1046       38871 :                                             spnego_state->mech_types.data,
    1047             :                                             spnego_state->mech_types.length,
    1048             :                                             &mech_list_mic);
    1049       38871 :                 if (!NT_STATUS_IS_OK(status)) {
    1050           0 :                         DBG_WARNING("failed to sign mechListMIC: %s\n",
    1051             :                                     nt_errstr(status));
    1052           0 :                         return status;
    1053             :                 }
    1054       38871 :                 spnego_state->needs_mic_sign = false;
    1055             :         }
    1056             : 
    1057       32054 :  client_response:
    1058      107154 :         if (sub_out.length == 0 && mech_list_mic.length == 0) {
    1059       65310 :                 *out = data_blob_null;
    1060             : 
    1061       65310 :                 if (!spnego_state->sub_sec_ready) {
    1062             :                         /* somethings wrong here... */
    1063           0 :                         DBG_ERR("gensec_update not ready without output\n");
    1064           0 :                         return NT_STATUS_INTERNAL_ERROR;
    1065             :                 }
    1066             : 
    1067       65310 :                 if (ta->negResult != SPNEGO_ACCEPT_COMPLETED) {
    1068             :                         /* unless of course it did not accept */
    1069           0 :                         DBG_WARNING("gensec_update ok but not accepted\n");
    1070           0 :                         return NT_STATUS_INVALID_PARAMETER;
    1071             :                 }
    1072             : 
    1073       65310 :                 if (!spnego_state->needs_mic_check) {
    1074       65310 :                         spnego_state->state_position = SPNEGO_DONE;
    1075       65310 :                         return NT_STATUS_OK;
    1076             :                 }
    1077             :         }
    1078             : 
    1079             :         /* compose reply */
    1080       41844 :         spnego_out.type = SPNEGO_NEG_TOKEN_TARG;
    1081       41844 :         spnego_out.negTokenTarg.negResult = SPNEGO_NONE_RESULT;
    1082       41844 :         spnego_out.negTokenTarg.supportedMech = NULL;
    1083       41844 :         spnego_out.negTokenTarg.responseToken = sub_out;
    1084       41844 :         spnego_out.negTokenTarg.mechListMIC = mech_list_mic;
    1085             : 
    1086       41844 :         if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
    1087           0 :                 DBG_WARNING("Failed to write NEG_TOKEN_TARG\n");
    1088           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1089             :         }
    1090             : 
    1091       41844 :         spnego_state->num_targs++;
    1092             : 
    1093             :         /* set next state */
    1094       41844 :         spnego_state->state_position = SPNEGO_CLIENT_TARG;
    1095       41844 :         spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
    1096             : 
    1097       41844 :         return NT_STATUS_MORE_PROCESSING_REQUIRED;
    1098             : }
    1099             : 
    1100             : static const struct spnego_neg_ops gensec_spnego_client_negTokenTarg_ops = {
    1101             :         .name      = "client_negTokenTarg",
    1102             :         .start_fn  = gensec_spnego_client_negTokenTarg_start,
    1103             :         .step_fn   = gensec_spnego_client_negTokenTarg_step,
    1104             :         .finish_fn = gensec_spnego_client_negTokenTarg_finish,
    1105             : };
    1106             : 
    1107             : /** create a server negTokenTarg 
    1108             :  *
    1109             :  * This is the case, where the client is the first one who sends data
    1110             : */
    1111             : 
    1112      107335 : static NTSTATUS gensec_spnego_server_response(struct spnego_state *spnego_state,
    1113             :                                               TALLOC_CTX *out_mem_ctx,
    1114             :                                               NTSTATUS nt_status,
    1115             :                                               const DATA_BLOB unwrapped_out,
    1116             :                                               DATA_BLOB mech_list_mic,
    1117             :                                               DATA_BLOB *out)
    1118             : {
    1119        1305 :         struct spnego_data spnego_out;
    1120             : 
    1121             :         /* compose reply */
    1122      107335 :         spnego_out.type = SPNEGO_NEG_TOKEN_TARG;
    1123      107335 :         spnego_out.negTokenTarg.responseToken = unwrapped_out;
    1124      107335 :         spnego_out.negTokenTarg.mechListMIC = mech_list_mic;
    1125      107335 :         spnego_out.negTokenTarg.supportedMech = NULL;
    1126             : 
    1127      107335 :         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {   
    1128       41819 :                 spnego_out.negTokenTarg.supportedMech = spnego_state->neg_oid;
    1129       41819 :                 if (spnego_state->mic_requested) {
    1130           2 :                         spnego_out.negTokenTarg.negResult = SPNEGO_REQUEST_MIC;
    1131           2 :                         spnego_state->mic_requested = false;
    1132             :                 } else {
    1133       41817 :                         spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
    1134             :                 }
    1135       41819 :                 spnego_state->state_position = SPNEGO_SERVER_TARG;
    1136       65516 :         } else if (NT_STATUS_IS_OK(nt_status)) {
    1137       65516 :                 if (unwrapped_out.data) {
    1138       27635 :                         spnego_out.negTokenTarg.supportedMech = spnego_state->neg_oid;
    1139             :                 }
    1140       65516 :                 spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED;
    1141       65516 :                 spnego_state->state_position = SPNEGO_DONE;
    1142             :         }
    1143             : 
    1144      107335 :         if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
    1145           0 :                 DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n"));
    1146           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1147             :         }
    1148             : 
    1149      107335 :         spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
    1150      107335 :         spnego_state->num_targs++;
    1151             : 
    1152      107335 :         return nt_status;
    1153             : }
    1154             : 
    1155       69647 : static NTSTATUS gensec_spnego_server_negTokenInit_start(
    1156             :                                         struct gensec_security *gensec_security,
    1157             :                                         struct spnego_state *spnego_state,
    1158             :                                         struct spnego_neg_state *n,
    1159             :                                         struct spnego_data *spnego_in,
    1160             :                                         TALLOC_CTX *in_mem_ctx,
    1161             :                                         DATA_BLOB *in_next)
    1162             : {
    1163        1053 :         bool ok;
    1164             : 
    1165       69647 :         n->mech_idx = 0;
    1166       69647 :         n->mech_types = spnego_in->negTokenInit.mechTypes;
    1167       69647 :         if (n->mech_types == NULL) {
    1168           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1169             :         }
    1170             : 
    1171       69647 :         n->all_idx = 0;
    1172       69647 :         n->all_sec = gensec_security_by_oid_list(gensec_security,
    1173             :                                                  n, n->mech_types,
    1174             :                                                  GENSEC_OID_SPNEGO);
    1175       69647 :         if (n->all_sec == NULL) {
    1176           0 :                 DBG_WARNING("gensec_security_by_oid_list() failed\n");
    1177           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1178             :         }
    1179             : 
    1180       69647 :         ok = spnego_write_mech_types(spnego_state,
    1181             :                                      n->mech_types,
    1182             :                                      &spnego_state->mech_types);
    1183       69647 :         if (!ok) {
    1184           0 :                 DBG_ERR("Failed to write mechTypes\n");
    1185           0 :                 return NT_STATUS_NO_MEMORY;
    1186             :         }
    1187             : 
    1188       69647 :         return n->ops->step_fn(gensec_security, spnego_state, n,
    1189       69647 :                                spnego_in, NT_STATUS_OK, in_mem_ctx, in_next);
    1190             : }
    1191             : 
    1192       69716 : static NTSTATUS gensec_spnego_server_negTokenInit_step(
    1193             :                                         struct gensec_security *gensec_security,
    1194             :                                         struct spnego_state *spnego_state,
    1195             :                                         struct spnego_neg_state *n,
    1196             :                                         struct spnego_data *spnego_in,
    1197             :                                         NTSTATUS last_status,
    1198             :                                         TALLOC_CTX *in_mem_ctx,
    1199             :                                         DATA_BLOB *in_next)
    1200             : {
    1201       69716 :         if (!NT_STATUS_IS_OK(last_status)) {
    1202          69 :                 const struct gensec_security_ops_wrapper *cur_sec =
    1203          69 :                         &n->all_sec[n->all_idx];
    1204          69 :                 const char *next_mech = n->mech_types[n->mech_idx+1];
    1205          69 :                 const struct gensec_security_ops_wrapper *next_sec = NULL;
    1206          69 :                 const char *next = NULL;
    1207          69 :                 int dbg_level = DBGLVL_WARNING;
    1208          69 :                 bool allow_fallback = false;
    1209          69 :                 NTSTATUS status = last_status;
    1210           0 :                 size_t i;
    1211             : 
    1212         136 :                 for (i = 0; next_mech != NULL && n->all_sec[i].op != NULL; i++) {
    1213          67 :                         if (strcmp(next_mech, n->all_sec[i].oid) != 0) {
    1214          67 :                                 continue;
    1215             :                         }
    1216             : 
    1217           0 :                         next_sec = &n->all_sec[i];
    1218           0 :                         break;
    1219             :                 }
    1220             : 
    1221          69 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
    1222          69 :                     NT_STATUS_EQUAL(status, NT_STATUS_CANT_ACCESS_DOMAIN_INFO))
    1223             :                 {
    1224           0 :                         allow_fallback = true;
    1225             :                 }
    1226             : 
    1227          69 :                 if (allow_fallback && next_sec != NULL) {
    1228           0 :                         next = next_sec->op->name;
    1229           0 :                         dbg_level = DBGLVL_NOTICE;
    1230             :                 }
    1231             : 
    1232          69 :                 DBG_PREFIX(dbg_level, (
    1233             :                            "%s: parsing NEG_TOKEN_INIT content failed "
    1234             :                            "(next[%s]): %s\n", cur_sec->op->name,
    1235             :                            next, nt_errstr(status)));
    1236             : 
    1237          69 :                 if (next == NULL) {
    1238             :                         /*
    1239             :                          * A hard error without a possible fallback.
    1240             :                          */
    1241          69 :                         return status;
    1242             :                 }
    1243             : 
    1244             :                 /*
    1245             :                  * Pretend we never started it
    1246             :                  */
    1247           0 :                 gensec_spnego_reset_sub_sec(spnego_state);
    1248             : 
    1249             :                 /*
    1250             :                  * And try the next one, based on the clients
    1251             :                  * mech type list...
    1252             :                  */
    1253           0 :                 n->mech_idx += 1;
    1254             :         }
    1255             : 
    1256             :         /*
    1257             :          * we always reset all_idx here, as the negotiation is
    1258             :          * done via mech_idx!
    1259             :          */
    1260       69647 :         n->all_idx = 0;
    1261             : 
    1262       69655 :         for (; n->mech_types[n->mech_idx] != NULL; n->mech_idx++) {
    1263       69653 :                 const char *cur_mech = n->mech_types[n->mech_idx];
    1264       69653 :                 const struct gensec_security_ops_wrapper *cur_sec = NULL;
    1265        1053 :                 NTSTATUS status;
    1266       69653 :                 DATA_BLOB sub_in = data_blob_null;
    1267        1053 :                 size_t i;
    1268             : 
    1269       69657 :                 for (i = 0; n->all_sec[i].op != NULL; i++) {
    1270       69649 :                         if (strcmp(cur_mech, n->all_sec[i].oid) != 0) {
    1271           4 :                                 continue;
    1272             :                         }
    1273             : 
    1274       69645 :                         cur_sec = &n->all_sec[i];
    1275       69645 :                         n->all_idx = i;
    1276       69645 :                         break;
    1277             :                 }
    1278             : 
    1279       69653 :                 if (cur_sec == NULL) {
    1280           8 :                         continue;
    1281             :                 }
    1282             : 
    1283       69645 :                 status = gensec_subcontext_start(spnego_state,
    1284             :                                                  gensec_security,
    1285             :                                                  &spnego_state->sub_sec_security);
    1286       69645 :                 if (!NT_STATUS_IS_OK(status)) {
    1287       68592 :                         return status;
    1288             :                 }
    1289             : 
    1290             :                 /* select the sub context */
    1291       70698 :                 status = gensec_start_mech_by_ops(spnego_state->sub_sec_security,
    1292       69645 :                                                   cur_sec->op);
    1293       69645 :                 if (!NT_STATUS_IS_OK(status)) {
    1294             :                         /*
    1295             :                          * Pretend we never started it
    1296             :                          */
    1297           0 :                         gensec_spnego_reset_sub_sec(spnego_state);
    1298           0 :                         continue;
    1299             :                 }
    1300             : 
    1301       69645 :                 if (n->mech_idx == 0) {
    1302             :                         /*
    1303             :                          * We can use the optimistic token.
    1304             :                          */
    1305       69643 :                         sub_in = spnego_in->negTokenInit.mechToken;
    1306             :                 } else {
    1307             :                         /*
    1308             :                          * Indicate the downgrade and request a
    1309             :                          * mic.
    1310             :                          */
    1311           2 :                         spnego_state->downgraded = true;
    1312           2 :                         spnego_state->mic_requested = true;
    1313             :                 }
    1314             : 
    1315       69645 :                 if (sub_in.length == 0) {
    1316           8 :                         spnego_state->no_optimistic = true;
    1317             :                 }
    1318             : 
    1319             :                 /*
    1320             :                  * Note that 'cur_sec' is temporary memory, but
    1321             :                  * cur_sec->oid points to a const string in the
    1322             :                  * backends gensec_security_ops structure.
    1323             :                  */
    1324       69645 :                 spnego_state->neg_oid = cur_sec->oid;
    1325             : 
    1326             :                 /* we need some content from the mech */
    1327       69645 :                 *in_next = sub_in;
    1328       69645 :                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
    1329             :         }
    1330             : 
    1331           2 :         DBG_WARNING("Could not find a suitable mechtype in NEG_TOKEN_INIT\n");
    1332           2 :         return NT_STATUS_INVALID_PARAMETER;
    1333             : }
    1334             : 
    1335       69576 : static NTSTATUS gensec_spnego_server_negTokenInit_finish(
    1336             :                                         struct gensec_security *gensec_security,
    1337             :                                         struct spnego_state *spnego_state,
    1338             :                                         struct spnego_neg_state *n,
    1339             :                                         struct spnego_data *spnego_in,
    1340             :                                         NTSTATUS sub_status,
    1341             :                                         const DATA_BLOB sub_out,
    1342             :                                         TALLOC_CTX *out_mem_ctx,
    1343             :                                         DATA_BLOB *out)
    1344             : {
    1345       69576 :         DATA_BLOB mech_list_mic = data_blob_null;
    1346             : 
    1347       69576 :         if (spnego_state->simulate_w2k) {
    1348             :                 /*
    1349             :                  * Windows 2000 returns the unwrapped token
    1350             :                  * also in the mech_list_mic field.
    1351             :                  *
    1352             :                  * In order to verify our client code,
    1353             :                  * we need a way to have a server with this
    1354             :                  * broken behaviour
    1355             :                  */
    1356        3348 :                 mech_list_mic = sub_out;
    1357             :         }
    1358             : 
    1359       69576 :         return gensec_spnego_server_response(spnego_state,
    1360             :                                              out_mem_ctx,
    1361             :                                              sub_status,
    1362             :                                              sub_out,
    1363             :                                              mech_list_mic,
    1364             :                                              out);
    1365             : }
    1366             : 
    1367             : static const struct spnego_neg_ops gensec_spnego_server_negTokenInit_ops = {
    1368             :         .name      = "server_negTokenInit",
    1369             :         .start_fn  = gensec_spnego_server_negTokenInit_start,
    1370             :         .step_fn   = gensec_spnego_server_negTokenInit_step,
    1371             :         .finish_fn = gensec_spnego_server_negTokenInit_finish,
    1372             : };
    1373             : 
    1374       41698 : static NTSTATUS gensec_spnego_server_negTokenTarg_start(
    1375             :                                         struct gensec_security *gensec_security,
    1376             :                                         struct spnego_state *spnego_state,
    1377             :                                         struct spnego_neg_state *n,
    1378             :                                         struct spnego_data *spnego_in,
    1379             :                                         TALLOC_CTX *in_mem_ctx,
    1380             :                                         DATA_BLOB *in_next)
    1381             : {
    1382       41698 :         const struct spnego_negTokenTarg *ta = &spnego_in->negTokenTarg;
    1383         261 :         NTSTATUS status;
    1384             : 
    1385       41698 :         spnego_state->num_targs++;
    1386             : 
    1387       41698 :         if (spnego_state->sub_sec_security == NULL) {
    1388           0 :                 DBG_ERR("SPNEGO: Did not setup a mech in NEG_TOKEN_INIT\n");
    1389           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1390             :         }
    1391             : 
    1392       41698 :         if (spnego_state->needs_mic_check) {
    1393           4 :                 if (ta->responseToken.length != 0) {
    1394           0 :                         DBG_WARNING("non empty response token not expected\n");
    1395           0 :                         return NT_STATUS_INVALID_PARAMETER;
    1396             :                 }
    1397             : 
    1398           4 :                 status = gensec_check_packet(spnego_state->sub_sec_security,
    1399           4 :                                              spnego_state->mech_types.data,
    1400             :                                              spnego_state->mech_types.length,
    1401           4 :                                              spnego_state->mech_types.data,
    1402             :                                              spnego_state->mech_types.length,
    1403             :                                              &ta->mechListMIC);
    1404           4 :                 if (!NT_STATUS_IS_OK(status)) {
    1405           0 :                         DBG_WARNING("failed to verify mechListMIC: %s\n",
    1406             :                                     nt_errstr(status));
    1407           0 :                         return status;
    1408             :                 }
    1409             : 
    1410           4 :                 spnego_state->needs_mic_check = false;
    1411           4 :                 spnego_state->done_mic_check = true;
    1412           4 :                 return NT_STATUS_OK;
    1413             :         }
    1414             : 
    1415       41694 :         if (!spnego_state->sub_sec_ready) {
    1416       41694 :                 *in_next = ta->responseToken;
    1417       41694 :                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
    1418             :         }
    1419             : 
    1420           0 :         return NT_STATUS_OK;
    1421             : }
    1422             : 
    1423        3939 : static NTSTATUS gensec_spnego_server_negTokenTarg_step(
    1424             :                                         struct gensec_security *gensec_security,
    1425             :                                         struct spnego_state *spnego_state,
    1426             :                                         struct spnego_neg_state *n,
    1427             :                                         struct spnego_data *spnego_in,
    1428             :                                         NTSTATUS last_status,
    1429             :                                         TALLOC_CTX *in_mem_ctx,
    1430             :                                         DATA_BLOB *in_next)
    1431             : {
    1432        3939 :         if (GENSEC_UPDATE_IS_NTERROR(last_status)) {
    1433        3939 :                 DBG_NOTICE("SPNEGO(%s) login failed: %s\n",
    1434             :                            spnego_state->sub_sec_security->ops->name,
    1435             :                            nt_errstr(last_status));
    1436        3939 :                 return last_status;
    1437             :         }
    1438             : 
    1439             :         /*
    1440             :          * This should never be reached!
    1441             :          * The step function is only called on errors!
    1442             :          */
    1443           0 :         smb_panic(__location__);
    1444             :         return NT_STATUS_INTERNAL_ERROR;
    1445             : }
    1446             : 
    1447       37759 : static NTSTATUS gensec_spnego_server_negTokenTarg_finish(
    1448             :                                         struct gensec_security *gensec_security,
    1449             :                                         struct spnego_state *spnego_state,
    1450             :                                         struct spnego_neg_state *n,
    1451             :                                         struct spnego_data *spnego_in,
    1452             :                                         NTSTATUS sub_status,
    1453             :                                         const DATA_BLOB sub_out,
    1454             :                                         TALLOC_CTX *out_mem_ctx,
    1455             :                                         DATA_BLOB *out)
    1456             : {
    1457       37759 :         const struct spnego_negTokenTarg *ta = &spnego_in->negTokenTarg;
    1458       37759 :         DATA_BLOB mech_list_mic = data_blob_null;
    1459         252 :         NTSTATUS status;
    1460       37759 :         bool have_sign = true;
    1461       37759 :         bool new_spnego = false;
    1462             : 
    1463       37759 :         status = sub_status;
    1464             : 
    1465       37759 :         if (!spnego_state->sub_sec_ready) {
    1466             :                 /*
    1467             :                  * We're not yet ready to deal with signatures.
    1468             :                  */
    1469           4 :                 goto server_response;
    1470             :         }
    1471             : 
    1472       37755 :         if (spnego_state->done_mic_check) {
    1473             :                 /*
    1474             :                  * We already checked the mic,
    1475             :                  * either the in last round here
    1476             :                  * in gensec_spnego_server_negTokenTarg_finish()
    1477             :                  * or during this round in
    1478             :                  * gensec_spnego_server_negTokenTarg_start().
    1479             :                  *
    1480             :                  * Both cases we're sure we don't have to
    1481             :                  * call gensec_sign_packet().
    1482             :                  */
    1483           4 :                 goto server_response;
    1484             :         }
    1485             : 
    1486       37751 :         have_sign = gensec_have_feature(spnego_state->sub_sec_security,
    1487             :                                         GENSEC_FEATURE_SIGN);
    1488       37751 :         if (spnego_state->simulate_w2k) {
    1489        1626 :                 have_sign = false;
    1490             :         }
    1491       37751 :         new_spnego = gensec_have_feature(spnego_state->sub_sec_security,
    1492             :                                          GENSEC_FEATURE_NEW_SPNEGO);
    1493       37751 :         if (ta->mechListMIC.length > 0) {
    1494       34809 :                 new_spnego = true;
    1495             :         }
    1496             : 
    1497       37751 :         if (have_sign && new_spnego) {
    1498       34787 :                 spnego_state->needs_mic_check = true;
    1499       34787 :                 spnego_state->needs_mic_sign = true;
    1500             :         }
    1501             : 
    1502       37751 :         if (have_sign && ta->mechListMIC.length > 0) {
    1503       35015 :                 status = gensec_check_packet(spnego_state->sub_sec_security,
    1504       34551 :                                              spnego_state->mech_types.data,
    1505             :                                              spnego_state->mech_types.length,
    1506       34783 :                                              spnego_state->mech_types.data,
    1507             :                                              spnego_state->mech_types.length,
    1508             :                                              &ta->mechListMIC);
    1509       34783 :                 if (!NT_STATUS_IS_OK(status)) {
    1510           0 :                         DBG_WARNING("failed to verify mechListMIC: %s\n",
    1511             :                                     nt_errstr(status));
    1512           0 :                         return status;
    1513             :                 }
    1514             : 
    1515       34783 :                 spnego_state->needs_mic_check = false;
    1516       34783 :                 spnego_state->done_mic_check = true;
    1517             :         }
    1518             : 
    1519       37751 :         if (spnego_state->needs_mic_sign) {
    1520       35019 :                 status = gensec_sign_packet(spnego_state->sub_sec_security,
    1521             :                                             n,
    1522       34555 :                                             spnego_state->mech_types.data,
    1523             :                                             spnego_state->mech_types.length,
    1524       34787 :                                             spnego_state->mech_types.data,
    1525             :                                             spnego_state->mech_types.length,
    1526             :                                             &mech_list_mic);
    1527       34787 :                 if (!NT_STATUS_IS_OK(status)) {
    1528           0 :                         DBG_WARNING("failed to sign mechListMIC: %s\n",
    1529             :                                     nt_errstr(status));
    1530           0 :                         return status;
    1531             :                 }
    1532       34787 :                 spnego_state->needs_mic_sign = false;
    1533             :         }
    1534             : 
    1535       37751 :         if (spnego_state->needs_mic_check) {
    1536           4 :                 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
    1537             :         }
    1538             : 
    1539       37747 :  server_response:
    1540       37759 :         return gensec_spnego_server_response(spnego_state,
    1541             :                                              out_mem_ctx,
    1542             :                                              status,
    1543             :                                              sub_out,
    1544             :                                              mech_list_mic,
    1545             :                                              out);
    1546             : }
    1547             : 
    1548             : static const struct spnego_neg_ops gensec_spnego_server_negTokenTarg_ops = {
    1549             :         .name      = "server_negTokenTarg",
    1550             :         .start_fn  = gensec_spnego_server_negTokenTarg_start,
    1551             :         .step_fn   = gensec_spnego_server_negTokenTarg_step,
    1552             :         .finish_fn = gensec_spnego_server_negTokenTarg_finish,
    1553             : };
    1554             : 
    1555             : struct gensec_spnego_update_state {
    1556             :         struct tevent_context *ev;
    1557             :         struct gensec_security *gensec;
    1558             :         struct spnego_state *spnego;
    1559             : 
    1560             :         DATA_BLOB full_in;
    1561             :         struct spnego_data _spnego_in;
    1562             :         struct spnego_data *spnego_in;
    1563             : 
    1564             :         struct {
    1565             :                 bool needed;
    1566             :                 DATA_BLOB in;
    1567             :                 NTSTATUS status;
    1568             :                 DATA_BLOB out;
    1569             :         } sub;
    1570             : 
    1571             :         struct spnego_neg_state *n;
    1572             : 
    1573             :         NTSTATUS status;
    1574             :         DATA_BLOB out;
    1575             : };
    1576             : 
    1577      689942 : static void gensec_spnego_update_cleanup(struct tevent_req *req,
    1578             :                                          enum tevent_req_state req_state)
    1579             : {
    1580       10536 :         struct gensec_spnego_update_state *state =
    1581      689942 :                 tevent_req_data(req,
    1582             :                 struct gensec_spnego_update_state);
    1583             : 
    1584      689942 :         switch (req_state) {
    1585        4335 :         case TEVENT_REQ_USER_ERROR:
    1586             :         case TEVENT_REQ_TIMED_OUT:
    1587             :         case TEVENT_REQ_NO_MEMORY:
    1588             :                 /*
    1589             :                  * A fatal error, further updates are not allowed.
    1590             :                  */
    1591        4335 :                 state->spnego->state_position = SPNEGO_DONE;
    1592        4335 :                 break;
    1593      675080 :         default:
    1594      675080 :                 break;
    1595             :         }
    1596      689942 : }
    1597             : 
    1598             : static NTSTATUS gensec_spnego_update_in(struct gensec_security *gensec_security,
    1599             :                                         const DATA_BLOB in, TALLOC_CTX *mem_ctx,
    1600             :                                         DATA_BLOB *full_in);
    1601             : static void gensec_spnego_update_pre(struct tevent_req *req);
    1602             : static void gensec_spnego_update_done(struct tevent_req *subreq);
    1603             : static void gensec_spnego_update_post(struct tevent_req *req);
    1604             : static NTSTATUS gensec_spnego_update_out(struct gensec_security *gensec_security,
    1605             :                                          TALLOC_CTX *out_mem_ctx,
    1606             :                                          DATA_BLOB *_out);
    1607             : 
    1608      344971 : static struct tevent_req *gensec_spnego_update_send(TALLOC_CTX *mem_ctx,
    1609             :                                                     struct tevent_context *ev,
    1610             :                                                     struct gensec_security *gensec_security,
    1611             :                                                     const DATA_BLOB in)
    1612             : {
    1613        5268 :         struct spnego_state *spnego_state =
    1614      344971 :                 talloc_get_type_abort(gensec_security->private_data,
    1615             :                 struct spnego_state);
    1616      344971 :         struct tevent_req *req = NULL;
    1617      344971 :         struct gensec_spnego_update_state *state = NULL;
    1618        5268 :         NTSTATUS status;
    1619        5268 :         ssize_t len;
    1620             : 
    1621      344971 :         req = tevent_req_create(mem_ctx, &state,
    1622             :                                 struct gensec_spnego_update_state);
    1623      344971 :         if (req == NULL) {
    1624           0 :                 return NULL;
    1625             :         }
    1626      344971 :         state->ev = ev;
    1627      344971 :         state->gensec = gensec_security;
    1628      344971 :         state->spnego = spnego_state;
    1629      344971 :         tevent_req_set_cleanup_fn(req, gensec_spnego_update_cleanup);
    1630             : 
    1631      344971 :         if (spnego_state->out_frag.length > 0) {
    1632        1486 :                 if (in.length > 0) {
    1633           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
    1634           0 :                         return tevent_req_post(req, ev);
    1635             :                 }
    1636             : 
    1637        1486 :                 status = gensec_spnego_update_out(gensec_security,
    1638        1486 :                                                   state, &state->out);
    1639        1486 :                 if (GENSEC_UPDATE_IS_NTERROR(status)) {
    1640           0 :                         tevent_req_nterror(req, status);
    1641           0 :                         return tevent_req_post(req, ev);
    1642             :                 }
    1643             : 
    1644        1486 :                 state->status = status;
    1645        1486 :                 tevent_req_done(req);
    1646        1486 :                 return tevent_req_post(req, ev);
    1647             :         }
    1648             : 
    1649      348753 :         status = gensec_spnego_update_in(gensec_security, in,
    1650      343485 :                                          state, &state->full_in);
    1651      343485 :         state->status = status;
    1652      343485 :         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
    1653        1486 :                 tevent_req_done(req);
    1654        1486 :                 return tevent_req_post(req, ev);
    1655             :         }
    1656      341999 :         if (tevent_req_nterror(req, status)) {
    1657           0 :                 return tevent_req_post(req, ev);
    1658             :         }
    1659             : 
    1660             :         /* Check if we got a valid SPNEGO blob... */
    1661             : 
    1662      341999 :         switch (spnego_state->state_position) {
    1663         102 :         case SPNEGO_FALLBACK:
    1664         102 :                 break;
    1665             : 
    1666      148951 :         case SPNEGO_CLIENT_TARG:
    1667             :         case SPNEGO_SERVER_TARG:
    1668      148951 :                 if (state->full_in.length == 0) {
    1669           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
    1670           0 :                         return tevent_req_post(req, ev);
    1671             :                 }
    1672             : 
    1673        5268 :                 FALL_THROUGH;
    1674             :         case SPNEGO_CLIENT_START:
    1675             :         case SPNEGO_SERVER_START:
    1676             : 
    1677      341897 :                 if (state->full_in.length == 0) {
    1678             :                         /* create_negTokenInit later */
    1679       82849 :                         break;
    1680             :                 }
    1681             : 
    1682      257528 :                 len = spnego_read_data(state,
    1683      253780 :                                        state->full_in,
    1684      253780 :                                        &state->_spnego_in);
    1685      257528 :                 if (len == -1) {
    1686         170 :                         if (spnego_state->state_position != SPNEGO_SERVER_START) {
    1687           0 :                                 DEBUG(1, ("Invalid SPNEGO request:\n"));
    1688           0 :                                 dump_data(1, state->full_in.data,
    1689           0 :                                           state->full_in.length);
    1690           0 :                                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
    1691           0 :                                 return tevent_req_post(req, ev);
    1692             :                         }
    1693             : 
    1694             :                         /*
    1695             :                          * This is the 'fallback' case, where we don't get
    1696             :                          * SPNEGO, and have to try all the other options (and
    1697             :                          * hope they all have a magic string they check)
    1698             :                          */
    1699         170 :                         status = gensec_spnego_server_try_fallback(gensec_security,
    1700             :                                                                    spnego_state,
    1701             :                                                                    state,
    1702         170 :                                                                    state->full_in);
    1703         170 :                         if (tevent_req_nterror(req, status)) {
    1704           0 :                                 return tevent_req_post(req, ev);
    1705             :                         }
    1706             : 
    1707             :                         /*
    1708             :                          * We'll continue with SPNEGO_FALLBACK below...
    1709             :                          */
    1710         170 :                         break;
    1711             :                 }
    1712      257358 :                 state->spnego_in = &state->_spnego_in;
    1713             : 
    1714             :                 /* OK, so it's real SPNEGO, check the packet's the one we expect */
    1715      257358 :                 if (state->spnego_in->type != spnego_state->expected_packet) {
    1716           0 :                         DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n",
    1717             :                                   state->spnego_in->type,
    1718             :                                   spnego_state->expected_packet));
    1719           0 :                         dump_data(1, state->full_in.data,
    1720           0 :                                   state->full_in.length);
    1721           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
    1722           0 :                         return tevent_req_post(req, ev);
    1723             :                 }
    1724             : 
    1725      253610 :                 break;
    1726             : 
    1727           0 :         default:
    1728           0 :                 smb_panic(__location__);
    1729             :                 return NULL;
    1730             :         }
    1731             : 
    1732      341999 :         gensec_spnego_update_pre(req);
    1733      341999 :         if (!tevent_req_is_in_progress(req)) {
    1734          22 :                 return tevent_req_post(req, ev);
    1735             :         }
    1736             : 
    1737      341977 :         if (state->sub.needed) {
    1738      252466 :                 struct tevent_req *subreq = NULL;
    1739             : 
    1740             :                 /*
    1741             :                  * We may need one more roundtrip...
    1742             :                  */
    1743      252466 :                 subreq = gensec_update_send(state, state->ev,
    1744             :                                             spnego_state->sub_sec_security,
    1745      248745 :                                             state->sub.in);
    1746      252466 :                 if (tevent_req_nomem(subreq, req)) {
    1747           0 :                         return tevent_req_post(req, ev);
    1748             :                 }
    1749      252466 :                 tevent_req_set_callback(subreq,
    1750             :                                         gensec_spnego_update_done,
    1751             :                                         req);
    1752      252466 :                 state->sub.needed = false;
    1753      252466 :                 return req;
    1754             :         }
    1755             : 
    1756       89511 :         gensec_spnego_update_post(req);
    1757       89511 :         if (!tevent_req_is_in_progress(req)) {
    1758       89511 :                 return tevent_req_post(req, ev);
    1759             :         }
    1760             : 
    1761           0 :         return req;
    1762             : }
    1763             : 
    1764      343485 : static NTSTATUS gensec_spnego_update_in(struct gensec_security *gensec_security,
    1765             :                                         const DATA_BLOB in, TALLOC_CTX *mem_ctx,
    1766             :                                         DATA_BLOB *full_in)
    1767             : {
    1768        5268 :         struct spnego_state *spnego_state =
    1769      343485 :                 talloc_get_type_abort(gensec_security->private_data,
    1770             :                 struct spnego_state);
    1771        5268 :         size_t expected;
    1772        5268 :         bool ok;
    1773             : 
    1774      343485 :         *full_in = data_blob_null;
    1775             : 
    1776      343485 :         switch (spnego_state->state_position) {
    1777         102 :         case SPNEGO_FALLBACK:
    1778         102 :                 *full_in = in;
    1779         102 :                 spnego_state->in_needed = 0;
    1780         102 :                 return NT_STATUS_OK;
    1781             : 
    1782      338115 :         case SPNEGO_CLIENT_START:
    1783             :         case SPNEGO_CLIENT_TARG:
    1784             :         case SPNEGO_SERVER_START:
    1785             :         case SPNEGO_SERVER_TARG:
    1786      343383 :                 break;
    1787             : 
    1788           0 :         case SPNEGO_DONE:
    1789             :         default:
    1790           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1791             :         }
    1792             : 
    1793      343383 :         if (spnego_state->in_needed == 0) {
    1794      341897 :                 size_t size = 0;
    1795        5268 :                 int ret;
    1796             : 
    1797             :                 /*
    1798             :                  * try to work out the size of the full
    1799             :                  * input token, it might be fragmented
    1800             :                  */
    1801      341897 :                 ret = asn1_peek_full_tag(in,  ASN1_APPLICATION(0), &size);
    1802      341897 :                 if ((ret != 0) && (ret != EAGAIN)) {
    1803      233422 :                         ret = asn1_peek_full_tag(in, ASN1_CONTEXT(1), &size);
    1804             :                 }
    1805             : 
    1806      341897 :                 if ((ret == 0) || (ret == EAGAIN)) {
    1807      257426 :                         spnego_state->in_needed = size;
    1808             :                 } else {
    1809             :                         /*
    1810             :                          * If it is not an asn1 message
    1811             :                          * just call the next layer.
    1812             :                          */
    1813       84471 :                         spnego_state->in_needed = in.length;
    1814             :                 }
    1815             :         }
    1816             : 
    1817      343383 :         if (spnego_state->in_needed > UINT16_MAX) {
    1818             :                 /*
    1819             :                  * limit the incoming message to 0xFFFF
    1820             :                  * to avoid DoS attacks.
    1821             :                  */
    1822           0 :                 return NT_STATUS_INVALID_BUFFER_SIZE;
    1823             :         }
    1824             : 
    1825      343383 :         if ((spnego_state->in_needed > 0) && (in.length == 0)) {
    1826             :                 /*
    1827             :                  * If we reach this, we know we got at least
    1828             :                  * part of an asn1 message, getting 0 means
    1829             :                  * the remote peer wants us to spin.
    1830             :                  */
    1831           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1832             :         }
    1833             : 
    1834      343383 :         expected = spnego_state->in_needed - spnego_state->in_frag.length;
    1835      343383 :         if (in.length > expected) {
    1836             :                 /*
    1837             :                  * we got more than expected
    1838             :                  */
    1839           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1840             :         }
    1841             : 
    1842      343383 :         if (in.length == spnego_state->in_needed) {
    1843             :                 /*
    1844             :                  * if the in.length contains the full blob
    1845             :                  * we are done.
    1846             :                  *
    1847             :                  * Note: this implies spnego_state->in_frag.length == 0,
    1848             :                  *       but we do not need to check this explicitly
    1849             :                  *       because we already know that we did not get
    1850             :                  *       more than expected.
    1851             :                  */
    1852      341893 :                 *full_in = in;
    1853      341893 :                 spnego_state->in_needed = 0;
    1854      341893 :                 return NT_STATUS_OK;
    1855             :         }
    1856             : 
    1857        1490 :         ok = data_blob_append(spnego_state, &spnego_state->in_frag,
    1858        1490 :                               in.data, in.length);
    1859        1490 :         if (!ok) {
    1860           0 :                 return NT_STATUS_NO_MEMORY;
    1861             :         }
    1862             : 
    1863        1490 :         if (spnego_state->in_needed > spnego_state->in_frag.length) {
    1864        1486 :                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
    1865             :         }
    1866             : 
    1867           4 :         *full_in = spnego_state->in_frag;
    1868           4 :         talloc_steal(mem_ctx, full_in->data);
    1869           4 :         spnego_state->in_frag = data_blob_null;
    1870           4 :         spnego_state->in_needed = 0;
    1871           4 :         return NT_STATUS_OK;
    1872             : }
    1873             : 
    1874      341999 : static void gensec_spnego_update_pre(struct tevent_req *req)
    1875             : {
    1876        5268 :         struct gensec_spnego_update_state *state =
    1877      341999 :                 tevent_req_data(req,
    1878             :                 struct gensec_spnego_update_state);
    1879      341999 :         struct spnego_state *spnego_state = state->spnego;
    1880      341999 :         const struct spnego_neg_ops *ops = NULL;
    1881        5268 :         NTSTATUS status;
    1882             : 
    1883      341999 :         state->sub.needed = false;
    1884      341999 :         state->sub.in = data_blob_null;
    1885      341999 :         state->sub.status = NT_STATUS_INTERNAL_ERROR;
    1886      341999 :         state->sub.out = data_blob_null;
    1887             : 
    1888      341999 :         if (spnego_state->state_position == SPNEGO_FALLBACK) {
    1889         272 :                 state->sub.in = state->full_in;
    1890         272 :                 state->full_in = data_blob_null;
    1891         272 :                 state->sub.needed = true;
    1892         294 :                 return;
    1893             :         }
    1894             : 
    1895      341727 :         switch (spnego_state->state_position) {
    1896       71584 :         case SPNEGO_CLIENT_START:
    1897       71584 :                 if (state->spnego_in == NULL) {
    1898             :                         /* client to produce negTokenInit */
    1899       32600 :                         ops = &gensec_spnego_create_negTokenInit_ops;
    1900       32600 :                         break;
    1901             :                 }
    1902             : 
    1903       38760 :                 ops = &gensec_spnego_client_negTokenInit_ops;
    1904       38760 :                 break;
    1905             : 
    1906      105950 :         case SPNEGO_CLIENT_TARG:
    1907      105950 :                 ops = &gensec_spnego_client_negTokenTarg_ops;
    1908      105950 :                 break;
    1909             : 
    1910      121192 :         case SPNEGO_SERVER_START:
    1911      121192 :                 if (state->spnego_in == NULL) {
    1912             :                         /* server to produce negTokenInit */
    1913       50249 :                         ops = &gensec_spnego_create_negTokenInit_ops;
    1914       50249 :                         break;
    1915             :                 }
    1916             : 
    1917       69647 :                 ops = &gensec_spnego_server_negTokenInit_ops;
    1918       69647 :                 break;
    1919             : 
    1920       41698 :         case SPNEGO_SERVER_TARG:
    1921       41698 :                 ops = &gensec_spnego_server_negTokenTarg_ops;
    1922       41698 :                 break;
    1923             : 
    1924           0 :         default:
    1925           0 :                 smb_panic(__location__);
    1926        5268 :                 return;
    1927             :         }
    1928             : 
    1929      341727 :         state->n = gensec_spnego_neg_state(state, ops);
    1930      341727 :         if (tevent_req_nomem(state->n, req)) {
    1931           0 :                 return;
    1932             :         }
    1933             : 
    1934      341727 :         status = ops->start_fn(state->gensec, spnego_state, state->n,
    1935             :                                state->spnego_in, state, &state->sub.in);
    1936      341727 :         if (GENSEC_UPDATE_IS_NTERROR(status)) {
    1937          22 :                 tevent_req_nterror(req, status);
    1938          22 :                 return;
    1939             :         }
    1940             : 
    1941      341705 :         if (NT_STATUS_IS_OK(status)) {
    1942             :                 /*
    1943             :                  * Call finish_fn() with an empty
    1944             :                  * blob and NT_STATUS_OK.
    1945             :                  */
    1946       89497 :                 state->sub.status = NT_STATUS_OK;
    1947      252208 :         } else if (spnego_state->state_position == SPNEGO_CLIENT_START &&
    1948       71566 :                    spnego_state->no_optimistic) {
    1949             :                 /*
    1950             :                  * Skip optimistic token per conf.
    1951             :                  */
    1952           6 :                 state->sub.status = NT_STATUS_MORE_PROCESSING_REQUIRED;
    1953      252202 :         } else if (spnego_state->state_position == SPNEGO_SERVER_START &&
    1954       69645 :                    state->sub.in.length == 0 && spnego_state->no_optimistic) {
    1955             :                 /*
    1956             :                  * If we didn't like the mechanism for which the client sent us
    1957             :                  * an optimistic token, or if he didn't send any, don't call
    1958             :                  * the sub mechanism just yet.
    1959             :                  */
    1960           8 :                 state->sub.status = NT_STATUS_MORE_PROCESSING_REQUIRED;
    1961           8 :                 spnego_state->no_optimistic = false;
    1962             :         } else {
    1963             :                 /*
    1964             :                  * MORE_PROCESSING_REQUIRED =>
    1965             :                  * we need to call gensec_update_send().
    1966             :                  */
    1967      252194 :                 state->sub.needed = true;
    1968             :         }
    1969             : }
    1970             : 
    1971      253695 : static void gensec_spnego_update_done(struct tevent_req *subreq)
    1972             : {
    1973        3721 :         struct tevent_req *req =
    1974      253695 :                 tevent_req_callback_data(subreq,
    1975             :                 struct tevent_req);
    1976        3721 :         struct gensec_spnego_update_state *state =
    1977      253695 :                 tevent_req_data(req,
    1978             :                 struct gensec_spnego_update_state);
    1979      253695 :         struct spnego_state *spnego_state = state->spnego;
    1980             : 
    1981      253695 :         state->sub.status = gensec_update_recv(subreq, state, &state->sub.out);
    1982      253695 :         TALLOC_FREE(subreq);
    1983      253695 :         if (NT_STATUS_IS_OK(state->sub.status)) {
    1984      135014 :                 spnego_state->sub_sec_ready = true;
    1985             :         }
    1986             : 
    1987      253695 :         gensec_spnego_update_post(req);
    1988      253695 : }
    1989             : 
    1990      343206 : static void gensec_spnego_update_post(struct tevent_req *req)
    1991             : {
    1992        5268 :         struct gensec_spnego_update_state *state =
    1993      343206 :                 tevent_req_data(req,
    1994             :                 struct gensec_spnego_update_state);
    1995      343206 :         struct spnego_state *spnego_state = state->spnego;
    1996      343206 :         const struct spnego_neg_ops *ops = NULL;
    1997        5268 :         NTSTATUS status;
    1998             : 
    1999      343206 :         state->sub.in = data_blob_null;
    2000      343206 :         state->sub.needed = false;
    2001             : 
    2002      343206 :         if (spnego_state->state_position == SPNEGO_FALLBACK) {
    2003         272 :                 status = state->sub.status;
    2004         272 :                 spnego_state->out_frag = state->sub.out;
    2005         272 :                 talloc_steal(spnego_state, spnego_state->out_frag.data);
    2006         272 :                 state->sub.out = data_blob_null;
    2007         272 :                 goto respond;
    2008             :         }
    2009             : 
    2010      342934 :         ops = state->n->ops;
    2011             : 
    2012      342934 :         if (GENSEC_UPDATE_IS_NTERROR(state->sub.status)) {
    2013             : 
    2014             : 
    2015             :                 /*
    2016             :                  * gensec_update_recv() returned an error,
    2017             :                  * let's see if the step_fn() want to
    2018             :                  * handle it and negotiate something else.
    2019             :                  */
    2020             : 
    2021        5542 :                 status = ops->step_fn(state->gensec,
    2022             :                                       spnego_state,
    2023             :                                       state->n,
    2024             :                                       state->spnego_in,
    2025             :                                       state->sub.status,
    2026             :                                       state,
    2027             :                                       &state->sub.in);
    2028        5542 :                 if (GENSEC_UPDATE_IS_NTERROR(status)) {
    2029        4313 :                         tevent_req_nterror(req, status);
    2030        4313 :                         return;
    2031             :                 }
    2032             : 
    2033        1229 :                 state->sub.out = data_blob_null;
    2034        1229 :                 state->sub.status = NT_STATUS_INTERNAL_ERROR;
    2035             : 
    2036        1229 :                 if (NT_STATUS_IS_OK(status)) {
    2037             :                         /*
    2038             :                          * Call finish_fn() with an empty
    2039             :                          * blob and NT_STATUS_OK.
    2040             :                          */
    2041           0 :                         state->sub.status = NT_STATUS_OK;
    2042             :                 } else {
    2043             :                         /*
    2044             :                          * MORE_PROCESSING_REQUIRED...
    2045             :                          */
    2046        1229 :                         state->sub.needed = true;
    2047             :                 }
    2048             :         }
    2049             : 
    2050      338621 :         if (state->sub.needed) {
    2051        1229 :                 struct tevent_req *subreq = NULL;
    2052             : 
    2053             :                 /*
    2054             :                  * We may need one more roundtrip...
    2055             :                  */
    2056        1229 :                 subreq = gensec_update_send(state, state->ev,
    2057             :                                             spnego_state->sub_sec_security,
    2058             :                                             state->sub.in);
    2059        1229 :                 if (tevent_req_nomem(subreq, req)) {
    2060           0 :                         return;
    2061             :                 }
    2062        1229 :                 tevent_req_set_callback(subreq,
    2063             :                                         gensec_spnego_update_done,
    2064             :                                         req);
    2065        1229 :                 state->sub.needed = false;
    2066        1229 :                 return;
    2067             :         }
    2068             : 
    2069      337392 :         status = ops->finish_fn(state->gensec,
    2070             :                                 spnego_state,
    2071             :                                 state->n,
    2072             :                                 state->spnego_in,
    2073             :                                 state->sub.status,
    2074             :                                 state->sub.out,
    2075             :                                 spnego_state,
    2076             :                                 &spnego_state->out_frag);
    2077      337392 :         TALLOC_FREE(state->n);
    2078      337392 :         if (GENSEC_UPDATE_IS_NTERROR(status)) {
    2079           0 :                 tevent_req_nterror(req, status);
    2080           0 :                 return;
    2081             :         }
    2082             : 
    2083      337392 :         if (NT_STATUS_IS_OK(status)) {
    2084      130826 :                 bool reset_full = true;
    2085             : 
    2086      130826 :                 reset_full = !spnego_state->done_mic_check;
    2087             : 
    2088      130826 :                 status = gensec_may_reset_crypto(spnego_state->sub_sec_security,
    2089             :                                                  reset_full);
    2090      130826 :                 if (tevent_req_nterror(req, status)) {
    2091           0 :                         return;
    2092             :                 }
    2093             :         }
    2094             : 
    2095      337392 : respond:
    2096      337664 :         spnego_state->out_status = status;
    2097             : 
    2098      337664 :         status = gensec_spnego_update_out(state->gensec,
    2099             :                                           state, &state->out);
    2100      337664 :         if (GENSEC_UPDATE_IS_NTERROR(status)) {
    2101           0 :                 tevent_req_nterror(req, status);
    2102           0 :                 return;
    2103             :         }
    2104             : 
    2105      337664 :         state->status = status;
    2106      337664 :         tevent_req_done(req);
    2107      337664 :         return;
    2108             : }
    2109             : 
    2110      339150 : static NTSTATUS gensec_spnego_update_out(struct gensec_security *gensec_security,
    2111             :                                          TALLOC_CTX *out_mem_ctx,
    2112             :                                          DATA_BLOB *_out)
    2113             : {
    2114        5259 :         struct spnego_state *spnego_state =
    2115      339150 :                 talloc_get_type_abort(gensec_security->private_data,
    2116             :                 struct spnego_state);
    2117      339150 :         DATA_BLOB out = data_blob_null;
    2118        5259 :         bool ok;
    2119             : 
    2120      339150 :         *_out = data_blob_null;
    2121             : 
    2122      339150 :         if (spnego_state->out_frag.length <= spnego_state->out_max_length) {
    2123             :                 /*
    2124             :                  * Fast path, we can deliver everything
    2125             :                  */
    2126             : 
    2127      337664 :                 *_out = spnego_state->out_frag;
    2128      337664 :                 if (spnego_state->out_frag.length > 0) {
    2129      272252 :                         talloc_steal(out_mem_ctx, _out->data);
    2130      272252 :                         spnego_state->out_frag = data_blob_null;
    2131             :                 }
    2132             : 
    2133      337664 :                 if (!NT_STATUS_IS_OK(spnego_state->out_status)) {
    2134      206668 :                         return spnego_state->out_status;
    2135             :                 }
    2136             : 
    2137             :                 /*
    2138             :                  * We're completely done, further updates are not allowed.
    2139             :                  */
    2140      130996 :                 spnego_state->state_position = SPNEGO_DONE;
    2141      130996 :                 return gensec_child_ready(gensec_security,
    2142             :                                           spnego_state->sub_sec_security);
    2143             :         }
    2144             : 
    2145        1486 :         out = spnego_state->out_frag;
    2146             : 
    2147             :         /*
    2148             :          * copy the remaining bytes
    2149             :          */
    2150        1486 :         spnego_state->out_frag = data_blob_talloc(spnego_state,
    2151             :                                         out.data + spnego_state->out_max_length,
    2152             :                                         out.length - spnego_state->out_max_length);
    2153        1486 :         if (spnego_state->out_frag.data == NULL) {
    2154           0 :                 return NT_STATUS_NO_MEMORY;
    2155             :         }
    2156             : 
    2157             :         /*
    2158             :          * truncate the buffer
    2159             :          */
    2160        1486 :         ok = data_blob_realloc(spnego_state, &out,
    2161             :                                spnego_state->out_max_length);
    2162        1486 :         if (!ok) {
    2163           0 :                 return NT_STATUS_NO_MEMORY;
    2164             :         }
    2165             : 
    2166        1486 :         talloc_steal(out_mem_ctx, out.data);
    2167        1486 :         *_out = out;
    2168        1486 :         return NT_STATUS_MORE_PROCESSING_REQUIRED;
    2169             : }
    2170             : 
    2171      344971 : static NTSTATUS gensec_spnego_update_recv(struct tevent_req *req,
    2172             :                                           TALLOC_CTX *out_mem_ctx,
    2173             :                                           DATA_BLOB *out)
    2174             : {
    2175        5268 :         struct gensec_spnego_update_state *state =
    2176      344971 :                 tevent_req_data(req,
    2177             :                 struct gensec_spnego_update_state);
    2178        5268 :         NTSTATUS status;
    2179             : 
    2180      344971 :         *out = data_blob_null;
    2181             : 
    2182      344971 :         if (tevent_req_is_nterror(req, &status)) {
    2183        4335 :                 tevent_req_received(req);
    2184        4335 :                 return status;
    2185             :         }
    2186             : 
    2187      340636 :         *out = state->out;
    2188      340636 :         talloc_steal(out_mem_ctx, state->out.data);
    2189      340636 :         status = state->status;
    2190      340636 :         tevent_req_received(req);
    2191      340636 :         return status;
    2192             : }
    2193             : 
    2194             : static const char *gensec_spnego_oids[] = { 
    2195             :         GENSEC_OID_SPNEGO,
    2196             :         NULL 
    2197             : };
    2198             : 
    2199             : static const struct gensec_security_ops gensec_spnego_security_ops = {
    2200             :         .name             = "spnego",
    2201             :         .sasl_name        = "GSS-SPNEGO",
    2202             :         .auth_type        = DCERPC_AUTH_TYPE_SPNEGO,
    2203             :         .oid              = gensec_spnego_oids,
    2204             :         .client_start     = gensec_spnego_client_start,
    2205             :         .server_start     = gensec_spnego_server_start,
    2206             :         .update_send      = gensec_spnego_update_send,
    2207             :         .update_recv      = gensec_spnego_update_recv,
    2208             :         .seal_packet      = gensec_child_seal_packet,
    2209             :         .sign_packet      = gensec_child_sign_packet,
    2210             :         .sig_size         = gensec_child_sig_size,
    2211             :         .max_wrapped_size = gensec_child_max_wrapped_size,
    2212             :         .max_input_size   = gensec_child_max_input_size,
    2213             :         .check_packet     = gensec_child_check_packet,
    2214             :         .unseal_packet    = gensec_child_unseal_packet,
    2215             :         .wrap             = gensec_child_wrap,
    2216             :         .unwrap           = gensec_child_unwrap,
    2217             :         .session_key      = gensec_child_session_key,
    2218             :         .session_info     = gensec_child_session_info,
    2219             :         .want_feature     = gensec_child_want_feature,
    2220             :         .have_feature     = gensec_child_have_feature,
    2221             :         .expire_time      = gensec_child_expire_time,
    2222             :         .final_auth_type  = gensec_child_final_auth_type,
    2223             :         .enabled          = true,
    2224             :         .priority         = GENSEC_SPNEGO,
    2225             :         .glue             = true,
    2226             : };
    2227             : 
    2228       53161 : _PUBLIC_ NTSTATUS gensec_spnego_init(TALLOC_CTX *ctx)
    2229             : {
    2230        1228 :         NTSTATUS ret;
    2231       53161 :         ret = gensec_register(ctx, &gensec_spnego_security_ops);
    2232       53161 :         if (!NT_STATUS_IS_OK(ret)) {
    2233           0 :                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
    2234             :                         gensec_spnego_security_ops.name));
    2235           0 :                 return ret;
    2236             :         }
    2237             : 
    2238       53161 :         return ret;
    2239             : }

Generated by: LCOV version 1.14