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