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