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