s4:torture/smb2: add smb2.delete-on-close-perms.BUG14427
[Samba.git] / auth / gensec / spnego.c
blobdb8a91b6f34a8a7f7ed05861a23b73ebbd2034da
1 /*
2 Unix SMB/CIFS implementation.
4 RFC2478 Compliant SPNEGO implementation
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
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.
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.
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/>.
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"
37 #undef DBGC_CLASS
38 #define DBGC_CLASS DBGC_AUTH
40 #undef strcasecmp
42 _PUBLIC_ NTSTATUS gensec_spnego_init(TALLOC_CTX *ctx);
44 enum spnego_state_position {
45 SPNEGO_SERVER_START,
46 SPNEGO_CLIENT_START,
47 SPNEGO_SERVER_TARG,
48 SPNEGO_CLIENT_TARG,
49 SPNEGO_FALLBACK,
50 SPNEGO_DONE
53 struct spnego_state;
54 struct spnego_neg_ops;
55 struct spnego_neg_state;
57 struct spnego_neg_state {
58 const struct spnego_neg_ops *ops;
59 const struct gensec_security_ops_wrapper *all_sec;
60 size_t all_idx;
61 const char * const *mech_types;
62 size_t mech_idx;
65 struct spnego_neg_ops {
66 const char *name;
68 * The start hook does the initial processing on the incoming paket and
69 * may starts the first possible subcontext. It indicates that
70 * gensec_update() is required on the subcontext by returning
71 * NT_STATUS_MORE_PROCESSING_REQUIRED and return something useful in
72 * 'in_next'. Note that 'in_mem_ctx' is just passed as a hint, the
73 * caller should treat 'in_next' as const and don't attempt to free the
74 * content. NT_STATUS_OK indicates the finish hook should be invoked
75 * directly within the need of gensec_update() on the subcontext.
76 * Every other error indicates an error that's returned to the caller.
78 NTSTATUS (*start_fn)(struct gensec_security *gensec_security,
79 struct spnego_state *spnego_state,
80 struct spnego_neg_state *n,
81 struct spnego_data *spnego_in,
82 TALLOC_CTX *in_mem_ctx,
83 DATA_BLOB *in_next);
85 * The step hook processes the result of a failed gensec_update() and
86 * can decide to ignore a failure and continue the negotiation by
87 * setting up the next possible subcontext. It indicates that
88 * gensec_update() is required on the subcontext by returning
89 * NT_STATUS_MORE_PROCESSING_REQUIRED and return something useful in
90 * 'in_next'. Note that 'in_mem_ctx' is just passed as a hint, the
91 * caller should treat 'in_next' as const and don't attempt to free the
92 * content. NT_STATUS_OK indicates the finish hook should be invoked
93 * directly within the need of gensec_update() on the subcontext.
94 * Every other error indicates an error that's returned to the caller.
96 NTSTATUS (*step_fn)(struct gensec_security *gensec_security,
97 struct spnego_state *spnego_state,
98 struct spnego_neg_state *n,
99 struct spnego_data *spnego_in,
100 NTSTATUS last_status,
101 TALLOC_CTX *in_mem_ctx,
102 DATA_BLOB *in_next);
104 * The finish hook processes the result of a successful gensec_update()
105 * (NT_STATUS_OK or NT_STATUS_MORE_PROCESSING_REQUIRED). It forms the
106 * response pdu that will be returned from the toplevel gensec_update()
107 * together with NT_STATUS_OK or NT_STATUS_MORE_PROCESSING_REQUIRED. It
108 * may also alter the state machine to prepare receiving the next pdu
109 * from the peer.
111 NTSTATUS (*finish_fn)(struct gensec_security *gensec_security,
112 struct spnego_state *spnego_state,
113 struct spnego_neg_state *n,
114 struct spnego_data *spnego_in,
115 NTSTATUS sub_status,
116 const DATA_BLOB sub_out,
117 TALLOC_CTX *out_mem_ctx,
118 DATA_BLOB *out);
121 struct spnego_state {
122 enum spnego_message_type expected_packet;
123 enum spnego_state_position state_position;
124 struct gensec_security *sub_sec_security;
125 bool sub_sec_ready;
127 const char *neg_oid;
129 DATA_BLOB mech_types;
130 size_t num_targs;
131 bool downgraded;
132 bool mic_requested;
133 bool needs_mic_sign;
134 bool needs_mic_check;
135 bool may_skip_mic_check;
136 bool done_mic_check;
138 bool simulate_w2k;
139 bool no_optimistic;
142 * The following is used to implement
143 * the update token fragmentation
145 size_t in_needed;
146 DATA_BLOB in_frag;
147 size_t out_max_length;
148 DATA_BLOB out_frag;
149 NTSTATUS out_status;
152 static struct spnego_neg_state *gensec_spnego_neg_state(TALLOC_CTX *mem_ctx,
153 const struct spnego_neg_ops *ops)
155 struct spnego_neg_state *n = NULL;
157 n = talloc_zero(mem_ctx, struct spnego_neg_state);
158 if (n == NULL) {
159 return NULL;
161 n->ops = ops;
163 return n;
166 static void gensec_spnego_reset_sub_sec(struct spnego_state *spnego_state)
168 spnego_state->sub_sec_ready = false;
169 TALLOC_FREE(spnego_state->sub_sec_security);
172 static NTSTATUS gensec_spnego_client_start(struct gensec_security *gensec_security)
174 struct spnego_state *spnego_state;
176 spnego_state = talloc_zero(gensec_security, struct spnego_state);
177 if (!spnego_state) {
178 return NT_STATUS_NO_MEMORY;
181 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT;
182 spnego_state->state_position = SPNEGO_CLIENT_START;
183 spnego_state->sub_sec_security = NULL;
184 spnego_state->sub_sec_ready = false;
185 spnego_state->mech_types = data_blob_null;
186 spnego_state->out_max_length = gensec_max_update_size(gensec_security);
187 spnego_state->out_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
189 spnego_state->simulate_w2k = gensec_setting_bool(gensec_security->settings,
190 "spnego", "simulate_w2k", false);
191 spnego_state->no_optimistic = gensec_setting_bool(gensec_security->settings,
192 "spnego",
193 "client_no_optimistic",
194 false);
196 gensec_security->private_data = spnego_state;
197 return NT_STATUS_OK;
200 static NTSTATUS gensec_spnego_server_start(struct gensec_security *gensec_security)
202 struct spnego_state *spnego_state;
204 spnego_state = talloc_zero(gensec_security, struct spnego_state);
205 if (!spnego_state) {
206 return NT_STATUS_NO_MEMORY;
209 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT;
210 spnego_state->state_position = SPNEGO_SERVER_START;
211 spnego_state->sub_sec_security = NULL;
212 spnego_state->sub_sec_ready = false;
213 spnego_state->mech_types = data_blob_null;
214 spnego_state->out_max_length = gensec_max_update_size(gensec_security);
215 spnego_state->out_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
217 spnego_state->simulate_w2k = gensec_setting_bool(gensec_security->settings,
218 "spnego", "simulate_w2k", false);
220 gensec_security->private_data = spnego_state;
221 return NT_STATUS_OK;
224 /** Fallback to another GENSEC mechanism, based on magic strings
226 * This is the 'fallback' case, where we don't get SPNEGO, and have to
227 * try all the other options (and hope they all have a magic string
228 * they check)
231 static NTSTATUS gensec_spnego_server_try_fallback(struct gensec_security *gensec_security,
232 struct spnego_state *spnego_state,
233 TALLOC_CTX *mem_ctx,
234 const DATA_BLOB in)
236 int i,j;
237 const struct gensec_security_ops **all_ops;
239 all_ops = gensec_security_mechs(gensec_security, mem_ctx);
241 for (i=0; all_ops && all_ops[i]; i++) {
242 bool is_spnego;
243 NTSTATUS nt_status;
245 if (gensec_security != NULL &&
246 !gensec_security_ops_enabled(all_ops[i], gensec_security))
248 continue;
251 if (!all_ops[i]->oid) {
252 continue;
255 is_spnego = false;
256 for (j=0; all_ops[i]->oid[j]; j++) {
257 if (strcasecmp(GENSEC_OID_SPNEGO,all_ops[i]->oid[j]) == 0) {
258 is_spnego = true;
261 if (is_spnego) {
262 continue;
265 if (!all_ops[i]->magic) {
266 continue;
269 nt_status = all_ops[i]->magic(gensec_security, &in);
270 if (!NT_STATUS_IS_OK(nt_status)) {
271 continue;
274 spnego_state->state_position = SPNEGO_FALLBACK;
276 nt_status = gensec_subcontext_start(spnego_state,
277 gensec_security,
278 &spnego_state->sub_sec_security);
280 if (!NT_STATUS_IS_OK(nt_status)) {
281 return nt_status;
283 /* select the sub context */
284 nt_status = gensec_start_mech_by_ops(spnego_state->sub_sec_security,
285 all_ops[i]);
286 if (!NT_STATUS_IS_OK(nt_status)) {
287 return nt_status;
290 return NT_STATUS_OK;
292 DEBUG(1, ("Failed to parse SPNEGO request\n"));
293 return NT_STATUS_INVALID_PARAMETER;
296 static NTSTATUS gensec_spnego_create_negTokenInit_start(
297 struct gensec_security *gensec_security,
298 struct spnego_state *spnego_state,
299 struct spnego_neg_state *n,
300 struct spnego_data *spnego_in,
301 TALLOC_CTX *in_mem_ctx,
302 DATA_BLOB *in_next)
304 n->mech_idx = 0;
305 n->mech_types = gensec_security_oids(gensec_security, n,
306 GENSEC_OID_SPNEGO);
307 if (n->mech_types == NULL) {
308 DBG_WARNING("gensec_security_oids() failed\n");
309 return NT_STATUS_NO_MEMORY;
312 n->all_idx = 0;
313 n->all_sec = gensec_security_by_oid_list(gensec_security,
314 n, n->mech_types,
315 GENSEC_OID_SPNEGO);
316 if (n->all_sec == NULL) {
317 DBG_WARNING("gensec_security_by_oid_list() failed\n");
318 return NT_STATUS_NO_MEMORY;
321 return n->ops->step_fn(gensec_security, spnego_state, n,
322 spnego_in, NT_STATUS_OK, in_mem_ctx, in_next);
325 static NTSTATUS gensec_spnego_create_negTokenInit_step(
326 struct gensec_security *gensec_security,
327 struct spnego_state *spnego_state,
328 struct spnego_neg_state *n,
329 struct spnego_data *spnego_in,
330 NTSTATUS last_status,
331 TALLOC_CTX *in_mem_ctx,
332 DATA_BLOB *in_next)
334 if (!NT_STATUS_IS_OK(last_status)) {
335 const struct gensec_security_ops_wrapper *cur_sec =
336 &n->all_sec[n->all_idx];
337 const struct gensec_security_ops_wrapper *next_sec = NULL;
338 const char *next = NULL;
339 const char *principal = NULL;
340 int dbg_level = DBGLVL_WARNING;
341 NTSTATUS status = last_status;
343 if (cur_sec[1].op != NULL) {
344 next_sec = &cur_sec[1];
347 if (next_sec != NULL) {
348 next = next_sec->op->name;
349 dbg_level = DBGLVL_NOTICE;
352 if (gensec_security->target.principal != NULL) {
353 principal = gensec_security->target.principal;
354 } else if (gensec_security->target.service != NULL &&
355 gensec_security->target.hostname != NULL)
357 principal = talloc_asprintf(spnego_state->sub_sec_security,
358 "%s/%s",
359 gensec_security->target.service,
360 gensec_security->target.hostname);
361 } else {
362 principal = gensec_security->target.hostname;
365 DBG_PREFIX(dbg_level, (
366 "%s: creating NEG_TOKEN_INIT for %s failed "
367 "(next[%s]): %s\n", cur_sec->op->name,
368 principal, next, nt_errstr(status)));
370 if (next == NULL) {
372 * A hard error without a possible fallback.
374 return status;
378 * Pretend we never started it
380 gensec_spnego_reset_sub_sec(spnego_state);
383 * And try the next one...
385 n->all_idx += 1;
388 for (; n->all_sec[n->all_idx].op != NULL; n->all_idx++) {
389 const struct gensec_security_ops_wrapper *cur_sec =
390 &n->all_sec[n->all_idx];
391 NTSTATUS status;
393 status = gensec_subcontext_start(spnego_state,
394 gensec_security,
395 &spnego_state->sub_sec_security);
396 if (!NT_STATUS_IS_OK(status)) {
397 return status;
400 /* select the sub context */
401 status = gensec_start_mech_by_ops(spnego_state->sub_sec_security,
402 cur_sec->op);
403 if (!NT_STATUS_IS_OK(status)) {
404 gensec_spnego_reset_sub_sec(spnego_state);
405 continue;
408 /* In the client, try and produce the first (optimistic) packet */
409 if (spnego_state->state_position == SPNEGO_CLIENT_START) {
410 *in_next = data_blob_null;
411 return NT_STATUS_MORE_PROCESSING_REQUIRED;
414 *in_next = data_blob_null;
415 return NT_STATUS_OK;
418 DBG_WARNING("Failed to setup SPNEGO negTokenInit request\n");
419 return NT_STATUS_INVALID_PARAMETER;
422 static NTSTATUS gensec_spnego_create_negTokenInit_finish(
423 struct gensec_security *gensec_security,
424 struct spnego_state *spnego_state,
425 struct spnego_neg_state *n,
426 struct spnego_data *spnego_in,
427 NTSTATUS sub_status,
428 const DATA_BLOB sub_out,
429 TALLOC_CTX *out_mem_ctx,
430 DATA_BLOB *out)
432 const struct gensec_security_ops_wrapper *cur_sec =
433 &n->all_sec[n->all_idx];
434 struct spnego_data spnego_out;
435 bool ok;
437 spnego_out.type = SPNEGO_NEG_TOKEN_INIT;
439 n->mech_types = gensec_security_oids_from_ops_wrapped(n, cur_sec);
440 if (n->mech_types == NULL) {
441 DBG_WARNING("gensec_security_oids_from_ops_wrapped() failed\n");
442 return NT_STATUS_NO_MEMORY;
445 ok = spnego_write_mech_types(spnego_state,
446 n->mech_types,
447 &spnego_state->mech_types);
448 if (!ok) {
449 DBG_ERR("Failed to write mechTypes\n");
450 return NT_STATUS_NO_MEMORY;
453 /* List the remaining mechs as options */
454 spnego_out.negTokenInit.mechTypes = n->mech_types;
455 spnego_out.negTokenInit.reqFlags = data_blob_null;
456 spnego_out.negTokenInit.reqFlagsPadding = 0;
458 if (spnego_state->state_position == SPNEGO_SERVER_START) {
459 spnego_out.negTokenInit.mechListMIC
460 = data_blob_string_const(ADS_IGNORE_PRINCIPAL);
461 } else {
462 spnego_out.negTokenInit.mechListMIC = data_blob_null;
465 spnego_out.negTokenInit.mechToken = sub_out;
467 if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
468 DBG_ERR("Failed to write NEG_TOKEN_INIT\n");
469 return NT_STATUS_INVALID_PARAMETER;
473 * Note that 'cur_sec' is temporary memory, but
474 * cur_sec->oid points to a const string in the
475 * backends gensec_security_ops structure.
477 spnego_state->neg_oid = cur_sec->oid;
479 /* set next state */
480 if (spnego_state->state_position == SPNEGO_SERVER_START) {
481 spnego_state->state_position = SPNEGO_SERVER_START;
482 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT;
483 } else {
484 spnego_state->state_position = SPNEGO_CLIENT_TARG;
485 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
488 return NT_STATUS_MORE_PROCESSING_REQUIRED;
491 static const struct spnego_neg_ops gensec_spnego_create_negTokenInit_ops = {
492 .name = "create_negTokenInit",
493 .start_fn = gensec_spnego_create_negTokenInit_start,
494 .step_fn = gensec_spnego_create_negTokenInit_step,
495 .finish_fn = gensec_spnego_create_negTokenInit_finish,
498 static NTSTATUS gensec_spnego_client_negTokenInit_start(
499 struct gensec_security *gensec_security,
500 struct spnego_state *spnego_state,
501 struct spnego_neg_state *n,
502 struct spnego_data *spnego_in,
503 TALLOC_CTX *in_mem_ctx,
504 DATA_BLOB *in_next)
506 const char *tp = NULL;
508 /* The server offers a list of mechanisms */
510 tp = spnego_in->negTokenInit.targetPrincipal;
511 if (tp != NULL && strcmp(tp, ADS_IGNORE_PRINCIPAL) != 0) {
512 DBG_INFO("Server claims it's principal name is %s\n", tp);
513 if (lpcfg_client_use_spnego_principal(gensec_security->settings->lp_ctx)) {
514 gensec_set_target_principal(gensec_security, tp);
518 n->mech_idx = 0;
520 /* Do not use server mech list as it isn't protected. Instead, get all
521 * supported mechs (excluding SPNEGO). */
522 n->mech_types = gensec_security_oids(gensec_security, n,
523 GENSEC_OID_SPNEGO);
524 if (n->mech_types == NULL) {
525 return NT_STATUS_INVALID_PARAMETER;
528 n->all_idx = 0;
529 n->all_sec = gensec_security_by_oid_list(gensec_security,
530 n, n->mech_types,
531 GENSEC_OID_SPNEGO);
532 if (n->all_sec == NULL) {
533 DBG_WARNING("gensec_security_by_oid_list() failed\n");
534 return NT_STATUS_INVALID_PARAMETER;
537 return n->ops->step_fn(gensec_security, spnego_state, n,
538 spnego_in, NT_STATUS_OK, in_mem_ctx, in_next);
541 static NTSTATUS gensec_spnego_client_negTokenInit_step(
542 struct gensec_security *gensec_security,
543 struct spnego_state *spnego_state,
544 struct spnego_neg_state *n,
545 struct spnego_data *spnego_in,
546 NTSTATUS last_status,
547 TALLOC_CTX *in_mem_ctx,
548 DATA_BLOB *in_next)
550 if (!NT_STATUS_IS_OK(last_status)) {
551 const struct gensec_security_ops_wrapper *cur_sec =
552 &n->all_sec[n->all_idx];
553 const struct gensec_security_ops_wrapper *next_sec = NULL;
554 const char *next = NULL;
555 const char *principal = NULL;
556 int dbg_level = DBGLVL_WARNING;
557 bool allow_fallback = false;
558 NTSTATUS status = last_status;
560 if (cur_sec[1].op != NULL) {
561 next_sec = &cur_sec[1];
565 * it is likely that a NULL input token will
566 * not be liked by most server mechs, but if
567 * we are in the client, we want the first
568 * update packet to be able to abort the use
569 * of this mech
571 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
572 NT_STATUS_EQUAL(status, NT_STATUS_NO_LOGON_SERVERS) ||
573 NT_STATUS_EQUAL(status, NT_STATUS_TIME_DIFFERENCE_AT_DC) ||
574 NT_STATUS_EQUAL(status, NT_STATUS_CANT_ACCESS_DOMAIN_INFO))
576 allow_fallback = true;
579 if (allow_fallback && next_sec != NULL) {
580 next = next_sec->op->name;
581 dbg_level = DBGLVL_NOTICE;
584 if (gensec_security->target.principal != NULL) {
585 principal = gensec_security->target.principal;
586 } else if (gensec_security->target.service != NULL &&
587 gensec_security->target.hostname != NULL)
589 principal = talloc_asprintf(spnego_state->sub_sec_security,
590 "%s/%s",
591 gensec_security->target.service,
592 gensec_security->target.hostname);
593 } else {
594 principal = gensec_security->target.hostname;
597 DBG_PREFIX(dbg_level, (
598 "%s: creating NEG_TOKEN_INIT for %s failed "
599 "(next[%s]): %s\n", cur_sec->op->name,
600 principal, next, nt_errstr(status)));
602 if (next == NULL) {
604 * A hard error without a possible fallback.
606 return status;
610 * Pretend we never started it.
612 gensec_spnego_reset_sub_sec(spnego_state);
615 * And try the next one...
617 n->all_idx += 1;
620 for (; n->all_sec[n->all_idx].op != NULL; n->all_idx++) {
621 const struct gensec_security_ops_wrapper *cur_sec =
622 &n->all_sec[n->all_idx];
623 NTSTATUS status;
625 status = gensec_subcontext_start(spnego_state,
626 gensec_security,
627 &spnego_state->sub_sec_security);
628 if (!NT_STATUS_IS_OK(status)) {
629 return status;
632 /* select the sub context */
633 status = gensec_start_mech_by_ops(spnego_state->sub_sec_security,
634 cur_sec->op);
635 if (!NT_STATUS_IS_OK(status)) {
636 gensec_spnego_reset_sub_sec(spnego_state);
637 continue;
641 * Note that 'cur_sec' is temporary memory, but
642 * cur_sec->oid points to a const string in the
643 * backends gensec_security_ops structure.
645 spnego_state->neg_oid = cur_sec->oid;
648 * As client we don't use an optimistic token from the server.
649 * But try to produce one for the server.
651 *in_next = data_blob_null;
652 return NT_STATUS_MORE_PROCESSING_REQUIRED;
655 DBG_WARNING("Could not find a suitable mechtype in NEG_TOKEN_INIT\n");
656 return NT_STATUS_INVALID_PARAMETER;
659 static NTSTATUS gensec_spnego_client_negTokenInit_finish(
660 struct gensec_security *gensec_security,
661 struct spnego_state *spnego_state,
662 struct spnego_neg_state *n,
663 struct spnego_data *spnego_in,
664 NTSTATUS sub_status,
665 const DATA_BLOB sub_out,
666 TALLOC_CTX *out_mem_ctx,
667 DATA_BLOB *out)
669 struct spnego_data spnego_out;
670 const char * const *mech_types = NULL;
671 bool ok;
673 if (n->mech_types == NULL) {
674 DBG_WARNING("No mech_types list\n");
675 return NT_STATUS_INVALID_PARAMETER;
678 for (mech_types = n->mech_types; *mech_types != NULL; mech_types++) {
679 int cmp = strcmp(*mech_types, spnego_state->neg_oid);
681 if (cmp == 0) {
682 break;
686 if (*mech_types == NULL) {
687 DBG_ERR("Can't find selected sub mechanism in mech_types\n");
688 return NT_STATUS_INVALID_PARAMETER;
691 /* compose reply */
692 spnego_out.type = SPNEGO_NEG_TOKEN_INIT;
693 spnego_out.negTokenInit.mechTypes = mech_types;
694 spnego_out.negTokenInit.reqFlags = data_blob_null;
695 spnego_out.negTokenInit.reqFlagsPadding = 0;
696 spnego_out.negTokenInit.mechListMIC = data_blob_null;
697 spnego_out.negTokenInit.mechToken = sub_out;
699 if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
700 DBG_ERR("Failed to write SPNEGO reply to NEG_TOKEN_INIT\n");
701 return NT_STATUS_INVALID_PARAMETER;
704 ok = spnego_write_mech_types(spnego_state,
705 mech_types,
706 &spnego_state->mech_types);
707 if (!ok) {
708 DBG_ERR("failed to write mechTypes\n");
709 return NT_STATUS_NO_MEMORY;
712 /* set next state */
713 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
714 spnego_state->state_position = SPNEGO_CLIENT_TARG;
716 return NT_STATUS_MORE_PROCESSING_REQUIRED;
719 static const struct spnego_neg_ops gensec_spnego_client_negTokenInit_ops = {
720 .name = "client_negTokenInit",
721 .start_fn = gensec_spnego_client_negTokenInit_start,
722 .step_fn = gensec_spnego_client_negTokenInit_step,
723 .finish_fn = gensec_spnego_client_negTokenInit_finish,
726 static NTSTATUS gensec_spnego_client_negTokenTarg_start(
727 struct gensec_security *gensec_security,
728 struct spnego_state *spnego_state,
729 struct spnego_neg_state *n,
730 struct spnego_data *spnego_in,
731 TALLOC_CTX *in_mem_ctx,
732 DATA_BLOB *in_next)
734 struct spnego_negTokenTarg *ta = &spnego_in->negTokenTarg;
735 NTSTATUS status;
737 spnego_state->num_targs++;
739 if (ta->negResult == SPNEGO_REJECT) {
740 return NT_STATUS_LOGON_FAILURE;
743 if (ta->negResult == SPNEGO_REQUEST_MIC) {
744 spnego_state->mic_requested = true;
747 if (ta->mechListMIC.length > 0) {
748 DATA_BLOB *m = &ta->mechListMIC;
749 const DATA_BLOB *r = &ta->responseToken;
752 * Windows 2000 has a bug, it repeats the
753 * responseToken in the mechListMIC field.
755 if (m->length == r->length) {
756 int cmp;
758 cmp = memcmp(m->data, r->data, m->length);
759 if (cmp == 0) {
760 data_blob_free(m);
765 /* Server didn't like our choice of mech, and chose something else */
766 if (((ta->negResult == SPNEGO_ACCEPT_INCOMPLETE) ||
767 (ta->negResult == SPNEGO_REQUEST_MIC)) &&
768 ta->supportedMech != NULL &&
769 strcmp(ta->supportedMech, spnego_state->neg_oid) != 0)
771 const char *client_mech = NULL;
772 const char *client_oid = NULL;
773 const char *server_mech = NULL;
774 const char *server_oid = NULL;
776 client_mech = gensec_get_name_by_oid(gensec_security,
777 spnego_state->neg_oid);
778 client_oid = spnego_state->neg_oid;
779 server_mech = gensec_get_name_by_oid(gensec_security,
780 ta->supportedMech);
781 server_oid = ta->supportedMech;
783 DBG_NOTICE("client preferred mech (%s[%s]) not accepted, "
784 "server wants: %s[%s]\n",
785 client_mech, client_oid, server_mech, server_oid);
787 spnego_state->downgraded = true;
788 gensec_spnego_reset_sub_sec(spnego_state);
790 status = gensec_subcontext_start(spnego_state,
791 gensec_security,
792 &spnego_state->sub_sec_security);
793 if (!NT_STATUS_IS_OK(status)) {
794 return status;
797 /* select the sub context */
798 status = gensec_start_mech_by_oid(spnego_state->sub_sec_security,
799 ta->supportedMech);
800 if (!NT_STATUS_IS_OK(status)) {
801 return status;
804 spnego_state->neg_oid = talloc_strdup(spnego_state,
805 ta->supportedMech);
806 if (spnego_state->neg_oid == NULL) {
807 return NT_STATUS_NO_MEMORY;
811 if (ta->mechListMIC.length > 0) {
812 if (spnego_state->sub_sec_ready) {
813 spnego_state->needs_mic_check = true;
817 if (spnego_state->needs_mic_check) {
818 if (ta->responseToken.length != 0) {
819 DBG_WARNING("non empty response token not expected\n");
820 return NT_STATUS_INVALID_PARAMETER;
823 if (ta->mechListMIC.length == 0
824 && spnego_state->may_skip_mic_check) {
826 * In this case we don't require
827 * a mechListMIC from the server.
829 * This works around bugs in the Azure
830 * and Apple spnego implementations.
832 * See
833 * https://bugzilla.samba.org/show_bug.cgi?id=11994
835 spnego_state->needs_mic_check = false;
836 return NT_STATUS_OK;
839 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 &ta->mechListMIC);
845 if (!NT_STATUS_IS_OK(status)) {
846 DBG_WARNING("failed to verify mechListMIC: %s\n",
847 nt_errstr(status));
848 return status;
850 spnego_state->needs_mic_check = false;
851 spnego_state->done_mic_check = true;
852 return NT_STATUS_OK;
855 if (!spnego_state->sub_sec_ready) {
856 *in_next = ta->responseToken;
857 return NT_STATUS_MORE_PROCESSING_REQUIRED;
860 return NT_STATUS_OK;
863 static NTSTATUS gensec_spnego_client_negTokenTarg_step(
864 struct gensec_security *gensec_security,
865 struct spnego_state *spnego_state,
866 struct spnego_neg_state *n,
867 struct spnego_data *spnego_in,
868 NTSTATUS last_status,
869 TALLOC_CTX *in_mem_ctx,
870 DATA_BLOB *in_next)
872 if (GENSEC_UPDATE_IS_NTERROR(last_status)) {
873 DBG_WARNING("SPNEGO(%s) login failed: %s\n",
874 spnego_state->sub_sec_security->ops->name,
875 nt_errstr(last_status));
876 return last_status;
880 * This should never be reached!
881 * The step function is only called on errors!
883 smb_panic(__location__);
884 return NT_STATUS_INTERNAL_ERROR;
887 static NTSTATUS gensec_spnego_client_negTokenTarg_finish(
888 struct gensec_security *gensec_security,
889 struct spnego_state *spnego_state,
890 struct spnego_neg_state *n,
891 struct spnego_data *spnego_in,
892 NTSTATUS sub_status,
893 const DATA_BLOB sub_out,
894 TALLOC_CTX *out_mem_ctx,
895 DATA_BLOB *out)
897 const struct spnego_negTokenTarg *ta =
898 &spnego_in->negTokenTarg;
899 DATA_BLOB mech_list_mic = data_blob_null;
900 NTSTATUS status;
901 struct spnego_data spnego_out;
903 if (!spnego_state->sub_sec_ready) {
905 * We're not yet ready to deal with signatures.
907 goto client_response;
910 if (spnego_state->done_mic_check) {
912 * We already checked the mic,
913 * either the in last round here
914 * in gensec_spnego_client_negTokenTarg_finish()
915 * or during this round in
916 * gensec_spnego_client_negTokenTarg_start().
918 * Both cases we're sure we don't have to
919 * call gensec_sign_packet().
921 goto client_response;
924 if (spnego_state->may_skip_mic_check) {
926 * This can only be set during
927 * the last round here in
928 * gensec_spnego_client_negTokenTarg_finish()
929 * below. And during this round
930 * we already passed the checks in
931 * gensec_spnego_client_negTokenTarg_start().
933 * So we need to skip to deal with
934 * any signatures now.
936 goto client_response;
939 if (!spnego_state->done_mic_check) {
940 bool have_sign = true;
941 bool new_spnego = false;
943 have_sign = gensec_have_feature(spnego_state->sub_sec_security,
944 GENSEC_FEATURE_SIGN);
945 if (spnego_state->simulate_w2k) {
946 have_sign = false;
948 new_spnego = gensec_have_feature(spnego_state->sub_sec_security,
949 GENSEC_FEATURE_NEW_SPNEGO);
951 switch (ta->negResult) {
952 case SPNEGO_ACCEPT_COMPLETED:
953 case SPNEGO_NONE_RESULT:
954 if (spnego_state->num_targs == 1) {
956 * the first exchange doesn't require
957 * verification
959 new_spnego = false;
962 break;
964 case SPNEGO_ACCEPT_INCOMPLETE:
965 if (ta->mechListMIC.length > 0) {
966 new_spnego = true;
967 break;
970 if (spnego_state->downgraded) {
972 * A downgrade should be protected if
973 * supported
975 break;
979 * The caller may just asked for
980 * GENSEC_FEATURE_SESSION_KEY, this
981 * is only reflected in the want_features.
983 * As it will imply
984 * gensec_have_features(GENSEC_FEATURE_SIGN)
985 * to return true.
987 if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
988 break;
990 if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
991 break;
994 * Here we're sure our preferred mech was
995 * selected by the server and our caller doesn't
996 * need GENSEC_FEATURE_SIGN nor
997 * GENSEC_FEATURE_SEAL support.
999 * In this case we don't require
1000 * a mechListMIC from the server.
1002 * This works around bugs in the Azure
1003 * and Apple spnego implementations.
1005 * See
1006 * https://bugzilla.samba.org/show_bug.cgi?id=11994
1008 spnego_state->may_skip_mic_check = true;
1009 break;
1011 case SPNEGO_REQUEST_MIC:
1012 if (ta->mechListMIC.length > 0) {
1013 new_spnego = true;
1015 break;
1016 default:
1017 break;
1020 if (spnego_state->mic_requested) {
1021 if (have_sign) {
1022 new_spnego = true;
1026 if (have_sign && new_spnego) {
1027 spnego_state->needs_mic_check = true;
1028 spnego_state->needs_mic_sign = true;
1032 if (ta->mechListMIC.length > 0) {
1033 status = gensec_check_packet(spnego_state->sub_sec_security,
1034 spnego_state->mech_types.data,
1035 spnego_state->mech_types.length,
1036 spnego_state->mech_types.data,
1037 spnego_state->mech_types.length,
1038 &ta->mechListMIC);
1039 if (!NT_STATUS_IS_OK(status)) {
1040 DBG_WARNING("failed to verify mechListMIC: %s\n",
1041 nt_errstr(status));
1042 return status;
1044 spnego_state->needs_mic_check = false;
1045 spnego_state->done_mic_check = true;
1048 if (spnego_state->needs_mic_sign) {
1049 status = gensec_sign_packet(spnego_state->sub_sec_security,
1051 spnego_state->mech_types.data,
1052 spnego_state->mech_types.length,
1053 spnego_state->mech_types.data,
1054 spnego_state->mech_types.length,
1055 &mech_list_mic);
1056 if (!NT_STATUS_IS_OK(status)) {
1057 DBG_WARNING("failed to sign mechListMIC: %s\n",
1058 nt_errstr(status));
1059 return status;
1061 spnego_state->needs_mic_sign = false;
1064 client_response:
1065 if (sub_out.length == 0 && mech_list_mic.length == 0) {
1066 *out = data_blob_null;
1068 if (!spnego_state->sub_sec_ready) {
1069 /* somethings wrong here... */
1070 DBG_ERR("gensec_update not ready without output\n");
1071 return NT_STATUS_INTERNAL_ERROR;
1074 if (ta->negResult != SPNEGO_ACCEPT_COMPLETED) {
1075 /* unless of course it did not accept */
1076 DBG_WARNING("gensec_update ok but not accepted\n");
1077 return NT_STATUS_INVALID_PARAMETER;
1080 if (!spnego_state->needs_mic_check) {
1081 spnego_state->state_position = SPNEGO_DONE;
1082 return NT_STATUS_OK;
1086 /* compose reply */
1087 spnego_out.type = SPNEGO_NEG_TOKEN_TARG;
1088 spnego_out.negTokenTarg.negResult = SPNEGO_NONE_RESULT;
1089 spnego_out.negTokenTarg.supportedMech = NULL;
1090 spnego_out.negTokenTarg.responseToken = sub_out;
1091 spnego_out.negTokenTarg.mechListMIC = mech_list_mic;
1093 if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
1094 DBG_WARNING("Failed to write NEG_TOKEN_TARG\n");
1095 return NT_STATUS_INVALID_PARAMETER;
1098 spnego_state->num_targs++;
1100 /* set next state */
1101 spnego_state->state_position = SPNEGO_CLIENT_TARG;
1102 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
1104 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1107 static const struct spnego_neg_ops gensec_spnego_client_negTokenTarg_ops = {
1108 .name = "client_negTokenTarg",
1109 .start_fn = gensec_spnego_client_negTokenTarg_start,
1110 .step_fn = gensec_spnego_client_negTokenTarg_step,
1111 .finish_fn = gensec_spnego_client_negTokenTarg_finish,
1114 /** create a server negTokenTarg
1116 * This is the case, where the client is the first one who sends data
1119 static NTSTATUS gensec_spnego_server_response(struct spnego_state *spnego_state,
1120 TALLOC_CTX *out_mem_ctx,
1121 NTSTATUS nt_status,
1122 const DATA_BLOB unwrapped_out,
1123 DATA_BLOB mech_list_mic,
1124 DATA_BLOB *out)
1126 struct spnego_data spnego_out;
1128 /* compose reply */
1129 spnego_out.type = SPNEGO_NEG_TOKEN_TARG;
1130 spnego_out.negTokenTarg.responseToken = unwrapped_out;
1131 spnego_out.negTokenTarg.mechListMIC = mech_list_mic;
1132 spnego_out.negTokenTarg.supportedMech = NULL;
1134 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1135 spnego_out.negTokenTarg.supportedMech = spnego_state->neg_oid;
1136 if (spnego_state->mic_requested) {
1137 spnego_out.negTokenTarg.negResult = SPNEGO_REQUEST_MIC;
1138 spnego_state->mic_requested = false;
1139 } else {
1140 spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
1142 spnego_state->state_position = SPNEGO_SERVER_TARG;
1143 } else if (NT_STATUS_IS_OK(nt_status)) {
1144 if (unwrapped_out.data) {
1145 spnego_out.negTokenTarg.supportedMech = spnego_state->neg_oid;
1147 spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED;
1148 spnego_state->state_position = SPNEGO_DONE;
1151 if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
1152 DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n"));
1153 return NT_STATUS_INVALID_PARAMETER;
1156 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
1157 spnego_state->num_targs++;
1159 return nt_status;
1162 static NTSTATUS gensec_spnego_server_negTokenInit_start(
1163 struct gensec_security *gensec_security,
1164 struct spnego_state *spnego_state,
1165 struct spnego_neg_state *n,
1166 struct spnego_data *spnego_in,
1167 TALLOC_CTX *in_mem_ctx,
1168 DATA_BLOB *in_next)
1170 bool ok;
1172 n->mech_idx = 0;
1173 n->mech_types = spnego_in->negTokenInit.mechTypes;
1174 if (n->mech_types == NULL) {
1175 return NT_STATUS_INVALID_PARAMETER;
1178 n->all_idx = 0;
1179 n->all_sec = gensec_security_by_oid_list(gensec_security,
1180 n, n->mech_types,
1181 GENSEC_OID_SPNEGO);
1182 if (n->all_sec == NULL) {
1183 DBG_WARNING("gensec_security_by_oid_list() failed\n");
1184 return NT_STATUS_INVALID_PARAMETER;
1187 ok = spnego_write_mech_types(spnego_state,
1188 n->mech_types,
1189 &spnego_state->mech_types);
1190 if (!ok) {
1191 DBG_ERR("Failed to write mechTypes\n");
1192 return NT_STATUS_NO_MEMORY;
1195 return n->ops->step_fn(gensec_security, spnego_state, n,
1196 spnego_in, NT_STATUS_OK, in_mem_ctx, in_next);
1199 static NTSTATUS gensec_spnego_server_negTokenInit_step(
1200 struct gensec_security *gensec_security,
1201 struct spnego_state *spnego_state,
1202 struct spnego_neg_state *n,
1203 struct spnego_data *spnego_in,
1204 NTSTATUS last_status,
1205 TALLOC_CTX *in_mem_ctx,
1206 DATA_BLOB *in_next)
1208 if (!NT_STATUS_IS_OK(last_status)) {
1209 const struct gensec_security_ops_wrapper *cur_sec =
1210 &n->all_sec[n->all_idx];
1211 const char *next_mech = n->mech_types[n->mech_idx+1];
1212 const struct gensec_security_ops_wrapper *next_sec = NULL;
1213 const char *next = NULL;
1214 int dbg_level = DBGLVL_WARNING;
1215 bool allow_fallback = false;
1216 NTSTATUS status = last_status;
1217 size_t i;
1219 for (i = 0; next_mech != NULL && n->all_sec[i].op != NULL; i++) {
1220 if (strcmp(next_mech, n->all_sec[i].oid) != 0) {
1221 continue;
1224 next_sec = &n->all_sec[i];
1225 break;
1228 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
1229 NT_STATUS_EQUAL(status, NT_STATUS_CANT_ACCESS_DOMAIN_INFO))
1231 allow_fallback = true;
1234 if (allow_fallback && next_sec != NULL) {
1235 next = next_sec->op->name;
1236 dbg_level = DBGLVL_NOTICE;
1239 DBG_PREFIX(dbg_level, (
1240 "%s: parsing NEG_TOKEN_INIT content failed "
1241 "(next[%s]): %s\n", cur_sec->op->name,
1242 next, nt_errstr(status)));
1244 if (next == NULL) {
1246 * A hard error without a possible fallback.
1248 return status;
1252 * Pretend we never started it
1254 gensec_spnego_reset_sub_sec(spnego_state);
1257 * And try the next one, based on the clients
1258 * mech type list...
1260 n->mech_idx += 1;
1264 * we always reset all_idx here, as the negotiation is
1265 * done via mech_idx!
1267 n->all_idx = 0;
1269 for (; n->mech_types[n->mech_idx] != NULL; n->mech_idx++) {
1270 const char *cur_mech = n->mech_types[n->mech_idx];
1271 const struct gensec_security_ops_wrapper *cur_sec = NULL;
1272 NTSTATUS status;
1273 DATA_BLOB sub_in = data_blob_null;
1274 size_t i;
1276 for (i = 0; n->all_sec[i].op != NULL; i++) {
1277 if (strcmp(cur_mech, n->all_sec[i].oid) != 0) {
1278 continue;
1281 cur_sec = &n->all_sec[i];
1282 n->all_idx = i;
1283 break;
1286 if (cur_sec == NULL) {
1287 continue;
1290 status = gensec_subcontext_start(spnego_state,
1291 gensec_security,
1292 &spnego_state->sub_sec_security);
1293 if (!NT_STATUS_IS_OK(status)) {
1294 return status;
1297 /* select the sub context */
1298 status = gensec_start_mech_by_ops(spnego_state->sub_sec_security,
1299 cur_sec->op);
1300 if (!NT_STATUS_IS_OK(status)) {
1302 * Pretend we never started it
1304 gensec_spnego_reset_sub_sec(spnego_state);
1305 continue;
1308 if (n->mech_idx == 0) {
1310 * We can use the optimistic token.
1312 sub_in = spnego_in->negTokenInit.mechToken;
1313 } else {
1315 * Indicate the downgrade and request a
1316 * mic.
1318 spnego_state->downgraded = true;
1319 spnego_state->mic_requested = true;
1322 if (sub_in.length == 0) {
1323 spnego_state->no_optimistic = true;
1327 * Note that 'cur_sec' is temporary memory, but
1328 * cur_sec->oid points to a const string in the
1329 * backends gensec_security_ops structure.
1331 spnego_state->neg_oid = cur_sec->oid;
1333 /* we need some content from the mech */
1334 *in_next = sub_in;
1335 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1338 DBG_WARNING("Could not find a suitable mechtype in NEG_TOKEN_INIT\n");
1339 return NT_STATUS_INVALID_PARAMETER;
1342 static NTSTATUS gensec_spnego_server_negTokenInit_finish(
1343 struct gensec_security *gensec_security,
1344 struct spnego_state *spnego_state,
1345 struct spnego_neg_state *n,
1346 struct spnego_data *spnego_in,
1347 NTSTATUS sub_status,
1348 const DATA_BLOB sub_out,
1349 TALLOC_CTX *out_mem_ctx,
1350 DATA_BLOB *out)
1352 DATA_BLOB mech_list_mic = data_blob_null;
1354 if (spnego_state->simulate_w2k) {
1356 * Windows 2000 returns the unwrapped token
1357 * also in the mech_list_mic field.
1359 * In order to verify our client code,
1360 * we need a way to have a server with this
1361 * broken behaviour
1363 mech_list_mic = sub_out;
1366 return gensec_spnego_server_response(spnego_state,
1367 out_mem_ctx,
1368 sub_status,
1369 sub_out,
1370 mech_list_mic,
1371 out);
1374 static const struct spnego_neg_ops gensec_spnego_server_negTokenInit_ops = {
1375 .name = "server_negTokenInit",
1376 .start_fn = gensec_spnego_server_negTokenInit_start,
1377 .step_fn = gensec_spnego_server_negTokenInit_step,
1378 .finish_fn = gensec_spnego_server_negTokenInit_finish,
1381 static NTSTATUS gensec_spnego_server_negTokenTarg_start(
1382 struct gensec_security *gensec_security,
1383 struct spnego_state *spnego_state,
1384 struct spnego_neg_state *n,
1385 struct spnego_data *spnego_in,
1386 TALLOC_CTX *in_mem_ctx,
1387 DATA_BLOB *in_next)
1389 const struct spnego_negTokenTarg *ta = &spnego_in->negTokenTarg;
1390 NTSTATUS status;
1392 spnego_state->num_targs++;
1394 if (spnego_state->sub_sec_security == NULL) {
1395 DBG_ERR("SPNEGO: Did not setup a mech in NEG_TOKEN_INIT\n");
1396 return NT_STATUS_INVALID_PARAMETER;
1399 if (spnego_state->needs_mic_check) {
1400 if (ta->responseToken.length != 0) {
1401 DBG_WARNING("non empty response token not expected\n");
1402 return NT_STATUS_INVALID_PARAMETER;
1405 status = gensec_check_packet(spnego_state->sub_sec_security,
1406 spnego_state->mech_types.data,
1407 spnego_state->mech_types.length,
1408 spnego_state->mech_types.data,
1409 spnego_state->mech_types.length,
1410 &ta->mechListMIC);
1411 if (!NT_STATUS_IS_OK(status)) {
1412 DBG_WARNING("failed to verify mechListMIC: %s\n",
1413 nt_errstr(status));
1414 return status;
1417 spnego_state->needs_mic_check = false;
1418 spnego_state->done_mic_check = true;
1419 return NT_STATUS_OK;
1422 if (!spnego_state->sub_sec_ready) {
1423 *in_next = ta->responseToken;
1424 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1427 return NT_STATUS_OK;
1430 static NTSTATUS gensec_spnego_server_negTokenTarg_step(
1431 struct gensec_security *gensec_security,
1432 struct spnego_state *spnego_state,
1433 struct spnego_neg_state *n,
1434 struct spnego_data *spnego_in,
1435 NTSTATUS last_status,
1436 TALLOC_CTX *in_mem_ctx,
1437 DATA_BLOB *in_next)
1439 if (GENSEC_UPDATE_IS_NTERROR(last_status)) {
1440 DBG_NOTICE("SPNEGO(%s) login failed: %s\n",
1441 spnego_state->sub_sec_security->ops->name,
1442 nt_errstr(last_status));
1443 return last_status;
1447 * This should never be reached!
1448 * The step function is only called on errors!
1450 smb_panic(__location__);
1451 return NT_STATUS_INTERNAL_ERROR;
1454 static NTSTATUS gensec_spnego_server_negTokenTarg_finish(
1455 struct gensec_security *gensec_security,
1456 struct spnego_state *spnego_state,
1457 struct spnego_neg_state *n,
1458 struct spnego_data *spnego_in,
1459 NTSTATUS sub_status,
1460 const DATA_BLOB sub_out,
1461 TALLOC_CTX *out_mem_ctx,
1462 DATA_BLOB *out)
1464 const struct spnego_negTokenTarg *ta = &spnego_in->negTokenTarg;
1465 DATA_BLOB mech_list_mic = data_blob_null;
1466 NTSTATUS status;
1467 bool have_sign = true;
1468 bool new_spnego = false;
1470 status = sub_status;
1472 if (!spnego_state->sub_sec_ready) {
1474 * We're not yet ready to deal with signatures.
1476 goto server_response;
1479 if (spnego_state->done_mic_check) {
1481 * We already checked the mic,
1482 * either the in last round here
1483 * in gensec_spnego_server_negTokenTarg_finish()
1484 * or during this round in
1485 * gensec_spnego_server_negTokenTarg_start().
1487 * Both cases we're sure we don't have to
1488 * call gensec_sign_packet().
1490 goto server_response;
1493 have_sign = gensec_have_feature(spnego_state->sub_sec_security,
1494 GENSEC_FEATURE_SIGN);
1495 if (spnego_state->simulate_w2k) {
1496 have_sign = false;
1498 new_spnego = gensec_have_feature(spnego_state->sub_sec_security,
1499 GENSEC_FEATURE_NEW_SPNEGO);
1500 if (ta->mechListMIC.length > 0) {
1501 new_spnego = true;
1504 if (have_sign && new_spnego) {
1505 spnego_state->needs_mic_check = true;
1506 spnego_state->needs_mic_sign = true;
1509 if (have_sign && ta->mechListMIC.length > 0) {
1510 status = gensec_check_packet(spnego_state->sub_sec_security,
1511 spnego_state->mech_types.data,
1512 spnego_state->mech_types.length,
1513 spnego_state->mech_types.data,
1514 spnego_state->mech_types.length,
1515 &ta->mechListMIC);
1516 if (!NT_STATUS_IS_OK(status)) {
1517 DBG_WARNING("failed to verify mechListMIC: %s\n",
1518 nt_errstr(status));
1519 return status;
1522 spnego_state->needs_mic_check = false;
1523 spnego_state->done_mic_check = true;
1526 if (spnego_state->needs_mic_sign) {
1527 status = gensec_sign_packet(spnego_state->sub_sec_security,
1529 spnego_state->mech_types.data,
1530 spnego_state->mech_types.length,
1531 spnego_state->mech_types.data,
1532 spnego_state->mech_types.length,
1533 &mech_list_mic);
1534 if (!NT_STATUS_IS_OK(status)) {
1535 DBG_WARNING("failed to sign mechListMIC: %s\n",
1536 nt_errstr(status));
1537 return status;
1539 spnego_state->needs_mic_sign = false;
1542 if (spnego_state->needs_mic_check) {
1543 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1546 server_response:
1547 return gensec_spnego_server_response(spnego_state,
1548 out_mem_ctx,
1549 status,
1550 sub_out,
1551 mech_list_mic,
1552 out);
1555 static const struct spnego_neg_ops gensec_spnego_server_negTokenTarg_ops = {
1556 .name = "server_negTokenTarg",
1557 .start_fn = gensec_spnego_server_negTokenTarg_start,
1558 .step_fn = gensec_spnego_server_negTokenTarg_step,
1559 .finish_fn = gensec_spnego_server_negTokenTarg_finish,
1562 struct gensec_spnego_update_state {
1563 struct tevent_context *ev;
1564 struct gensec_security *gensec;
1565 struct spnego_state *spnego;
1567 DATA_BLOB full_in;
1568 struct spnego_data _spnego_in;
1569 struct spnego_data *spnego_in;
1571 struct {
1572 bool needed;
1573 DATA_BLOB in;
1574 NTSTATUS status;
1575 DATA_BLOB out;
1576 } sub;
1578 struct spnego_neg_state *n;
1580 NTSTATUS status;
1581 DATA_BLOB out;
1584 static void gensec_spnego_update_cleanup(struct tevent_req *req,
1585 enum tevent_req_state req_state)
1587 struct gensec_spnego_update_state *state =
1588 tevent_req_data(req,
1589 struct gensec_spnego_update_state);
1591 switch (req_state) {
1592 case TEVENT_REQ_USER_ERROR:
1593 case TEVENT_REQ_TIMED_OUT:
1594 case TEVENT_REQ_NO_MEMORY:
1596 * A fatal error, further updates are not allowed.
1598 state->spnego->state_position = SPNEGO_DONE;
1599 break;
1600 default:
1601 break;
1605 static NTSTATUS gensec_spnego_update_in(struct gensec_security *gensec_security,
1606 const DATA_BLOB in, TALLOC_CTX *mem_ctx,
1607 DATA_BLOB *full_in);
1608 static void gensec_spnego_update_pre(struct tevent_req *req);
1609 static void gensec_spnego_update_done(struct tevent_req *subreq);
1610 static void gensec_spnego_update_post(struct tevent_req *req);
1611 static NTSTATUS gensec_spnego_update_out(struct gensec_security *gensec_security,
1612 TALLOC_CTX *out_mem_ctx,
1613 DATA_BLOB *_out);
1615 static struct tevent_req *gensec_spnego_update_send(TALLOC_CTX *mem_ctx,
1616 struct tevent_context *ev,
1617 struct gensec_security *gensec_security,
1618 const DATA_BLOB in)
1620 struct spnego_state *spnego_state =
1621 talloc_get_type_abort(gensec_security->private_data,
1622 struct spnego_state);
1623 struct tevent_req *req = NULL;
1624 struct gensec_spnego_update_state *state = NULL;
1625 NTSTATUS status;
1626 ssize_t len;
1628 req = tevent_req_create(mem_ctx, &state,
1629 struct gensec_spnego_update_state);
1630 if (req == NULL) {
1631 return NULL;
1633 state->ev = ev;
1634 state->gensec = gensec_security;
1635 state->spnego = spnego_state;
1636 tevent_req_set_cleanup_fn(req, gensec_spnego_update_cleanup);
1638 if (spnego_state->out_frag.length > 0) {
1639 if (in.length > 0) {
1640 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1641 return tevent_req_post(req, ev);
1644 status = gensec_spnego_update_out(gensec_security,
1645 state, &state->out);
1646 if (GENSEC_UPDATE_IS_NTERROR(status)) {
1647 tevent_req_nterror(req, status);
1648 return tevent_req_post(req, ev);
1651 state->status = status;
1652 tevent_req_done(req);
1653 return tevent_req_post(req, ev);
1656 status = gensec_spnego_update_in(gensec_security, in,
1657 state, &state->full_in);
1658 state->status = status;
1659 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1660 tevent_req_done(req);
1661 return tevent_req_post(req, ev);
1663 if (tevent_req_nterror(req, status)) {
1664 return tevent_req_post(req, ev);
1667 /* Check if we got a valid SPNEGO blob... */
1669 switch (spnego_state->state_position) {
1670 case SPNEGO_FALLBACK:
1671 break;
1673 case SPNEGO_CLIENT_TARG:
1674 case SPNEGO_SERVER_TARG:
1675 if (state->full_in.length == 0) {
1676 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1677 return tevent_req_post(req, ev);
1680 FALL_THROUGH;
1681 case SPNEGO_CLIENT_START:
1682 case SPNEGO_SERVER_START:
1684 if (state->full_in.length == 0) {
1685 /* create_negTokenInit later */
1686 break;
1689 len = spnego_read_data(state,
1690 state->full_in,
1691 &state->_spnego_in);
1692 if (len == -1) {
1693 if (spnego_state->state_position != SPNEGO_SERVER_START) {
1694 DEBUG(1, ("Invalid SPNEGO request:\n"));
1695 dump_data(1, state->full_in.data,
1696 state->full_in.length);
1697 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1698 return tevent_req_post(req, ev);
1702 * This is the 'fallback' case, where we don't get
1703 * SPNEGO, and have to try all the other options (and
1704 * hope they all have a magic string they check)
1706 status = gensec_spnego_server_try_fallback(gensec_security,
1707 spnego_state,
1708 state,
1709 state->full_in);
1710 if (tevent_req_nterror(req, status)) {
1711 return tevent_req_post(req, ev);
1715 * We'll continue with SPNEGO_FALLBACK below...
1717 break;
1719 state->spnego_in = &state->_spnego_in;
1721 /* OK, so it's real SPNEGO, check the packet's the one we expect */
1722 if (state->spnego_in->type != spnego_state->expected_packet) {
1723 DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n",
1724 state->spnego_in->type,
1725 spnego_state->expected_packet));
1726 dump_data(1, state->full_in.data,
1727 state->full_in.length);
1728 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1729 return tevent_req_post(req, ev);
1732 break;
1734 default:
1735 smb_panic(__location__);
1736 return NULL;
1739 gensec_spnego_update_pre(req);
1740 if (!tevent_req_is_in_progress(req)) {
1741 return tevent_req_post(req, ev);
1744 if (state->sub.needed) {
1745 struct tevent_req *subreq = NULL;
1748 * We may need one more roundtrip...
1750 subreq = gensec_update_send(state, state->ev,
1751 spnego_state->sub_sec_security,
1752 state->sub.in);
1753 if (tevent_req_nomem(subreq, req)) {
1754 return tevent_req_post(req, ev);
1756 tevent_req_set_callback(subreq,
1757 gensec_spnego_update_done,
1758 req);
1759 state->sub.needed = false;
1760 return req;
1763 gensec_spnego_update_post(req);
1764 if (!tevent_req_is_in_progress(req)) {
1765 return tevent_req_post(req, ev);
1768 return req;
1771 static NTSTATUS gensec_spnego_update_in(struct gensec_security *gensec_security,
1772 const DATA_BLOB in, TALLOC_CTX *mem_ctx,
1773 DATA_BLOB *full_in)
1775 struct spnego_state *spnego_state =
1776 talloc_get_type_abort(gensec_security->private_data,
1777 struct spnego_state);
1778 size_t expected;
1779 bool ok;
1781 *full_in = data_blob_null;
1783 switch (spnego_state->state_position) {
1784 case SPNEGO_FALLBACK:
1785 *full_in = in;
1786 spnego_state->in_needed = 0;
1787 return NT_STATUS_OK;
1789 case SPNEGO_CLIENT_START:
1790 case SPNEGO_CLIENT_TARG:
1791 case SPNEGO_SERVER_START:
1792 case SPNEGO_SERVER_TARG:
1793 break;
1795 case SPNEGO_DONE:
1796 default:
1797 return NT_STATUS_INVALID_PARAMETER;
1800 if (spnego_state->in_needed == 0) {
1801 size_t size = 0;
1802 int ret;
1805 * try to work out the size of the full
1806 * input token, it might be fragmented
1808 ret = asn1_peek_full_tag(in, ASN1_APPLICATION(0), &size);
1809 if ((ret != 0) && (ret != EAGAIN)) {
1810 ret = asn1_peek_full_tag(in, ASN1_CONTEXT(1), &size);
1813 if ((ret == 0) || (ret == EAGAIN)) {
1814 spnego_state->in_needed = size;
1815 } else {
1817 * If it is not an asn1 message
1818 * just call the next layer.
1820 spnego_state->in_needed = in.length;
1824 if (spnego_state->in_needed > UINT16_MAX) {
1826 * limit the incoming message to 0xFFFF
1827 * to avoid DoS attacks.
1829 return NT_STATUS_INVALID_BUFFER_SIZE;
1832 if ((spnego_state->in_needed > 0) && (in.length == 0)) {
1834 * If we reach this, we know we got at least
1835 * part of an asn1 message, getting 0 means
1836 * the remote peer wants us to spin.
1838 return NT_STATUS_INVALID_PARAMETER;
1841 expected = spnego_state->in_needed - spnego_state->in_frag.length;
1842 if (in.length > expected) {
1844 * we got more than expected
1846 return NT_STATUS_INVALID_PARAMETER;
1849 if (in.length == spnego_state->in_needed) {
1851 * if the in.length contains the full blob
1852 * we are done.
1854 * Note: this implies spnego_state->in_frag.length == 0,
1855 * but we do not need to check this explicitly
1856 * because we already know that we did not get
1857 * more than expected.
1859 *full_in = in;
1860 spnego_state->in_needed = 0;
1861 return NT_STATUS_OK;
1864 ok = data_blob_append(spnego_state, &spnego_state->in_frag,
1865 in.data, in.length);
1866 if (!ok) {
1867 return NT_STATUS_NO_MEMORY;
1870 if (spnego_state->in_needed > spnego_state->in_frag.length) {
1871 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1874 *full_in = spnego_state->in_frag;
1875 talloc_steal(mem_ctx, full_in->data);
1876 spnego_state->in_frag = data_blob_null;
1877 spnego_state->in_needed = 0;
1878 return NT_STATUS_OK;
1881 static void gensec_spnego_update_pre(struct tevent_req *req)
1883 struct gensec_spnego_update_state *state =
1884 tevent_req_data(req,
1885 struct gensec_spnego_update_state);
1886 struct spnego_state *spnego_state = state->spnego;
1887 const struct spnego_neg_ops *ops = NULL;
1888 NTSTATUS status;
1890 state->sub.needed = false;
1891 state->sub.in = data_blob_null;
1892 state->sub.status = NT_STATUS_INTERNAL_ERROR;
1893 state->sub.out = data_blob_null;
1895 if (spnego_state->state_position == SPNEGO_FALLBACK) {
1896 state->sub.in = state->full_in;
1897 state->full_in = data_blob_null;
1898 state->sub.needed = true;
1899 return;
1902 switch (spnego_state->state_position) {
1903 case SPNEGO_CLIENT_START:
1904 if (state->spnego_in == NULL) {
1905 /* client to produce negTokenInit */
1906 ops = &gensec_spnego_create_negTokenInit_ops;
1907 break;
1910 ops = &gensec_spnego_client_negTokenInit_ops;
1911 break;
1913 case SPNEGO_CLIENT_TARG:
1914 ops = &gensec_spnego_client_negTokenTarg_ops;
1915 break;
1917 case SPNEGO_SERVER_START:
1918 if (state->spnego_in == NULL) {
1919 /* server to produce negTokenInit */
1920 ops = &gensec_spnego_create_negTokenInit_ops;
1921 break;
1924 ops = &gensec_spnego_server_negTokenInit_ops;
1925 break;
1927 case SPNEGO_SERVER_TARG:
1928 ops = &gensec_spnego_server_negTokenTarg_ops;
1929 break;
1931 default:
1932 smb_panic(__location__);
1933 return;
1936 state->n = gensec_spnego_neg_state(state, ops);
1937 if (tevent_req_nomem(state->n, req)) {
1938 return;
1941 status = ops->start_fn(state->gensec, spnego_state, state->n,
1942 state->spnego_in, state, &state->sub.in);
1943 if (GENSEC_UPDATE_IS_NTERROR(status)) {
1944 tevent_req_nterror(req, status);
1945 return;
1948 if (NT_STATUS_IS_OK(status)) {
1950 * Call finish_fn() with an empty
1951 * blob and NT_STATUS_OK.
1953 state->sub.status = NT_STATUS_OK;
1954 } else if (spnego_state->state_position == SPNEGO_CLIENT_START &&
1955 spnego_state->no_optimistic) {
1957 * Skip optimistic token per conf.
1959 state->sub.status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1960 } else if (spnego_state->state_position == SPNEGO_SERVER_START &&
1961 state->sub.in.length == 0 && spnego_state->no_optimistic) {
1963 * If we didn't like the mechanism for which the client sent us
1964 * an optimistic token, or if he didn't send any, don't call
1965 * the sub mechanism just yet.
1967 state->sub.status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1968 spnego_state->no_optimistic = false;
1969 } else {
1971 * MORE_PROCESSING_REQUIRED =>
1972 * we need to call gensec_update_send().
1974 state->sub.needed = true;
1978 static void gensec_spnego_update_done(struct tevent_req *subreq)
1980 struct tevent_req *req =
1981 tevent_req_callback_data(subreq,
1982 struct tevent_req);
1983 struct gensec_spnego_update_state *state =
1984 tevent_req_data(req,
1985 struct gensec_spnego_update_state);
1986 struct spnego_state *spnego_state = state->spnego;
1988 state->sub.status = gensec_update_recv(subreq, state, &state->sub.out);
1989 TALLOC_FREE(subreq);
1990 if (NT_STATUS_IS_OK(state->sub.status)) {
1991 spnego_state->sub_sec_ready = true;
1994 gensec_spnego_update_post(req);
1997 static void gensec_spnego_update_post(struct tevent_req *req)
1999 struct gensec_spnego_update_state *state =
2000 tevent_req_data(req,
2001 struct gensec_spnego_update_state);
2002 struct spnego_state *spnego_state = state->spnego;
2003 const struct spnego_neg_ops *ops = NULL;
2004 NTSTATUS status;
2006 state->sub.in = data_blob_null;
2007 state->sub.needed = false;
2009 if (spnego_state->state_position == SPNEGO_FALLBACK) {
2010 status = state->sub.status;
2011 spnego_state->out_frag = state->sub.out;
2012 talloc_steal(spnego_state, spnego_state->out_frag.data);
2013 state->sub.out = data_blob_null;
2014 goto respond;
2017 ops = state->n->ops;
2019 if (GENSEC_UPDATE_IS_NTERROR(state->sub.status)) {
2023 * gensec_update_recv() returned an error,
2024 * let's see if the step_fn() want to
2025 * handle it and negotiate something else.
2028 status = ops->step_fn(state->gensec,
2029 spnego_state,
2030 state->n,
2031 state->spnego_in,
2032 state->sub.status,
2033 state,
2034 &state->sub.in);
2035 if (GENSEC_UPDATE_IS_NTERROR(status)) {
2036 tevent_req_nterror(req, status);
2037 return;
2040 state->sub.out = data_blob_null;
2041 state->sub.status = NT_STATUS_INTERNAL_ERROR;
2043 if (NT_STATUS_IS_OK(status)) {
2045 * Call finish_fn() with an empty
2046 * blob and NT_STATUS_OK.
2048 state->sub.status = NT_STATUS_OK;
2049 } else {
2051 * MORE_PROCESSING_REQUIRED...
2053 state->sub.needed = true;
2057 if (state->sub.needed) {
2058 struct tevent_req *subreq = NULL;
2061 * We may need one more roundtrip...
2063 subreq = gensec_update_send(state, state->ev,
2064 spnego_state->sub_sec_security,
2065 state->sub.in);
2066 if (tevent_req_nomem(subreq, req)) {
2067 return;
2069 tevent_req_set_callback(subreq,
2070 gensec_spnego_update_done,
2071 req);
2072 state->sub.needed = false;
2073 return;
2076 status = ops->finish_fn(state->gensec,
2077 spnego_state,
2078 state->n,
2079 state->spnego_in,
2080 state->sub.status,
2081 state->sub.out,
2082 spnego_state,
2083 &spnego_state->out_frag);
2084 TALLOC_FREE(state->n);
2085 if (GENSEC_UPDATE_IS_NTERROR(status)) {
2086 tevent_req_nterror(req, status);
2087 return;
2090 if (NT_STATUS_IS_OK(status)) {
2091 bool reset_full = true;
2093 reset_full = !spnego_state->done_mic_check;
2095 status = gensec_may_reset_crypto(spnego_state->sub_sec_security,
2096 reset_full);
2097 if (tevent_req_nterror(req, status)) {
2098 return;
2102 respond:
2103 spnego_state->out_status = status;
2105 status = gensec_spnego_update_out(state->gensec,
2106 state, &state->out);
2107 if (GENSEC_UPDATE_IS_NTERROR(status)) {
2108 tevent_req_nterror(req, status);
2109 return;
2112 state->status = status;
2113 tevent_req_done(req);
2114 return;
2117 static NTSTATUS gensec_spnego_update_out(struct gensec_security *gensec_security,
2118 TALLOC_CTX *out_mem_ctx,
2119 DATA_BLOB *_out)
2121 struct spnego_state *spnego_state =
2122 talloc_get_type_abort(gensec_security->private_data,
2123 struct spnego_state);
2124 DATA_BLOB out = data_blob_null;
2125 bool ok;
2127 *_out = data_blob_null;
2129 if (spnego_state->out_frag.length <= spnego_state->out_max_length) {
2131 * Fast path, we can deliver everything
2134 *_out = spnego_state->out_frag;
2135 if (spnego_state->out_frag.length > 0) {
2136 talloc_steal(out_mem_ctx, _out->data);
2137 spnego_state->out_frag = data_blob_null;
2140 if (!NT_STATUS_IS_OK(spnego_state->out_status)) {
2141 return spnego_state->out_status;
2145 * We're completely done, further updates are not allowed.
2147 spnego_state->state_position = SPNEGO_DONE;
2148 return gensec_child_ready(gensec_security,
2149 spnego_state->sub_sec_security);
2152 out = spnego_state->out_frag;
2155 * copy the remaining bytes
2157 spnego_state->out_frag = data_blob_talloc(spnego_state,
2158 out.data + spnego_state->out_max_length,
2159 out.length - spnego_state->out_max_length);
2160 if (spnego_state->out_frag.data == NULL) {
2161 return NT_STATUS_NO_MEMORY;
2165 * truncate the buffer
2167 ok = data_blob_realloc(spnego_state, &out,
2168 spnego_state->out_max_length);
2169 if (!ok) {
2170 return NT_STATUS_NO_MEMORY;
2173 talloc_steal(out_mem_ctx, out.data);
2174 *_out = out;
2175 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2178 static NTSTATUS gensec_spnego_update_recv(struct tevent_req *req,
2179 TALLOC_CTX *out_mem_ctx,
2180 DATA_BLOB *out)
2182 struct gensec_spnego_update_state *state =
2183 tevent_req_data(req,
2184 struct gensec_spnego_update_state);
2185 NTSTATUS status;
2187 *out = data_blob_null;
2189 if (tevent_req_is_nterror(req, &status)) {
2190 tevent_req_received(req);
2191 return status;
2194 *out = state->out;
2195 talloc_steal(out_mem_ctx, state->out.data);
2196 status = state->status;
2197 tevent_req_received(req);
2198 return status;
2201 static const char *gensec_spnego_oids[] = {
2202 GENSEC_OID_SPNEGO,
2203 NULL
2206 static const struct gensec_security_ops gensec_spnego_security_ops = {
2207 .name = "spnego",
2208 .sasl_name = "GSS-SPNEGO",
2209 .auth_type = DCERPC_AUTH_TYPE_SPNEGO,
2210 .oid = gensec_spnego_oids,
2211 .client_start = gensec_spnego_client_start,
2212 .server_start = gensec_spnego_server_start,
2213 .update_send = gensec_spnego_update_send,
2214 .update_recv = gensec_spnego_update_recv,
2215 .seal_packet = gensec_child_seal_packet,
2216 .sign_packet = gensec_child_sign_packet,
2217 .sig_size = gensec_child_sig_size,
2218 .max_wrapped_size = gensec_child_max_wrapped_size,
2219 .max_input_size = gensec_child_max_input_size,
2220 .check_packet = gensec_child_check_packet,
2221 .unseal_packet = gensec_child_unseal_packet,
2222 .wrap = gensec_child_wrap,
2223 .unwrap = gensec_child_unwrap,
2224 .session_key = gensec_child_session_key,
2225 .session_info = gensec_child_session_info,
2226 .want_feature = gensec_child_want_feature,
2227 .have_feature = gensec_child_have_feature,
2228 .expire_time = gensec_child_expire_time,
2229 .final_auth_type = gensec_child_final_auth_type,
2230 .enabled = true,
2231 .priority = GENSEC_SPNEGO,
2232 .glue = true,
2235 _PUBLIC_ NTSTATUS gensec_spnego_init(TALLOC_CTX *ctx)
2237 NTSTATUS ret;
2238 ret = gensec_register(ctx, &gensec_spnego_security_ops);
2239 if (!NT_STATUS_IS_OK(ret)) {
2240 DEBUG(0,("Failed to register '%s' gensec backend!\n",
2241 gensec_spnego_security_ops.name));
2242 return ret;
2245 return ret;