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