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