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