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