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