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

Generated by: LCOV version 1.14