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/>.
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"
39 _PUBLIC_ NTSTATUS gensec_spnego_init(TALLOC_CTX *ctx);
41 enum spnego_state_position {
51 struct spnego_neg_ops;
52 struct spnego_neg_state;
54 struct spnego_neg_state {
55 const struct spnego_neg_ops *ops;
56 const struct gensec_security_ops_wrapper *all_sec;
58 const char * const *mech_types;
62 struct spnego_neg_ops {
65 * The start hook does the initial processing on the incoming paket and
66 * may starts the first possible subcontext. It indicates that
67 * gensec_update() is required on the subcontext by returning
68 * NT_STATUS_MORE_PROCESSING_REQUIRED and return something useful in
69 * 'in_next'. Note that 'in_mem_ctx' is just passed as a hint, the
70 * caller should treat 'in_next' as const and don't attempt to free the
71 * content. NT_STATUS_OK indicates the finish hook should be invoked
72 * directly withing the need of gensec_update() on the subcontext.
73 * Every other error indicates an error that's returned to the caller.
75 NTSTATUS (*start_fn)(struct gensec_security *gensec_security,
76 struct spnego_state *spnego_state,
77 struct spnego_neg_state *n,
78 struct spnego_data *spnego_in,
79 TALLOC_CTX *in_mem_ctx,
82 * The step hook processes the result of a failed gensec_update() and
83 * can decide to ignore a failure and continue the negotiation by
84 * setting up the next possible subcontext. It indicates that
85 * gensec_update() is required on the subcontext by returning
86 * NT_STATUS_MORE_PROCESSING_REQUIRED and return something useful in
87 * 'in_next'. Note that 'in_mem_ctx' is just passed as a hint, the
88 * caller should treat 'in_next' as const and don't attempt to free the
89 * content. NT_STATUS_OK indicates the finish hook should be invoked
90 * directly withing the need of gensec_update() on the subcontext.
91 * Every other error indicates an error that's returned to the caller.
93 NTSTATUS (*step_fn)(struct gensec_security *gensec_security,
94 struct spnego_state *spnego_state,
95 struct spnego_neg_state *n,
96 struct spnego_data *spnego_in,
98 TALLOC_CTX *in_mem_ctx,
101 * The finish hook processes the result of a successful gensec_update()
102 * (NT_STATUS_OK or NT_STATUS_MORE_PROCESSING_REQUIRED). It forms the
103 * response pdu that will be returned from the toplevel gensec_update()
104 * together with NT_STATUS_OK or NT_STATUS_MORE_PROCESSING_REQUIRED. It
105 * may also alter the state machine to prepare receiving the next pdu
108 NTSTATUS (*finish_fn)(struct gensec_security *gensec_security,
109 struct spnego_state *spnego_state,
110 struct spnego_neg_state *n,
111 struct spnego_data *spnego_in,
113 const DATA_BLOB sub_out,
114 TALLOC_CTX *out_mem_ctx,
118 struct spnego_state {
119 enum spnego_message_type expected_packet;
120 enum spnego_state_position state_position;
121 struct gensec_security *sub_sec_security;
126 DATA_BLOB mech_types;
131 bool needs_mic_check;
132 bool may_skip_mic_check;
138 * The following is used to implement
139 * the update token fragmentation
143 size_t out_max_length;
148 static struct spnego_neg_state *gensec_spnego_neg_state(TALLOC_CTX *mem_ctx,
149 const struct spnego_neg_ops *ops)
151 struct spnego_neg_state *n = NULL;
153 n = talloc_zero(mem_ctx, struct spnego_neg_state);
162 static void gensec_spnego_reset_sub_sec(struct spnego_state *spnego_state)
164 spnego_state->sub_sec_ready = false;
165 TALLOC_FREE(spnego_state->sub_sec_security);
168 static NTSTATUS gensec_spnego_client_start(struct gensec_security *gensec_security)
170 struct spnego_state *spnego_state;
172 spnego_state = talloc_zero(gensec_security, struct spnego_state);
174 return NT_STATUS_NO_MEMORY;
177 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT;
178 spnego_state->state_position = SPNEGO_CLIENT_START;
179 spnego_state->sub_sec_security = NULL;
180 spnego_state->sub_sec_ready = false;
181 spnego_state->mech_types = data_blob_null;
182 spnego_state->out_max_length = gensec_max_update_size(gensec_security);
183 spnego_state->out_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
185 spnego_state->simulate_w2k = gensec_setting_bool(gensec_security->settings,
186 "spnego", "simulate_w2k", false);
188 gensec_security->private_data = spnego_state;
192 static NTSTATUS gensec_spnego_server_start(struct gensec_security *gensec_security)
194 struct spnego_state *spnego_state;
196 spnego_state = talloc_zero(gensec_security, struct spnego_state);
198 return NT_STATUS_NO_MEMORY;
201 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT;
202 spnego_state->state_position = SPNEGO_SERVER_START;
203 spnego_state->sub_sec_security = NULL;
204 spnego_state->sub_sec_ready = false;
205 spnego_state->mech_types = data_blob_null;
206 spnego_state->out_max_length = gensec_max_update_size(gensec_security);
207 spnego_state->out_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
209 spnego_state->simulate_w2k = gensec_setting_bool(gensec_security->settings,
210 "spnego", "simulate_w2k", false);
212 gensec_security->private_data = spnego_state;
216 /** Fallback to another GENSEC mechanism, based on magic strings
218 * This is the 'fallback' case, where we don't get SPNEGO, and have to
219 * try all the other options (and hope they all have a magic string
223 static NTSTATUS gensec_spnego_server_try_fallback(struct gensec_security *gensec_security,
224 struct spnego_state *spnego_state,
229 const struct gensec_security_ops **all_ops;
231 all_ops = gensec_security_mechs(gensec_security, mem_ctx);
233 for (i=0; all_ops && all_ops[i]; i++) {
237 if (gensec_security != NULL &&
238 !gensec_security_ops_enabled(all_ops[i], gensec_security))
243 if (!all_ops[i]->oid) {
248 for (j=0; all_ops[i]->oid[j]; j++) {
249 if (strcasecmp(GENSEC_OID_SPNEGO,all_ops[i]->oid[j]) == 0) {
257 if (!all_ops[i]->magic) {
261 nt_status = all_ops[i]->magic(gensec_security, &in);
262 if (!NT_STATUS_IS_OK(nt_status)) {
266 spnego_state->state_position = SPNEGO_FALLBACK;
268 nt_status = gensec_subcontext_start(spnego_state,
270 &spnego_state->sub_sec_security);
272 if (!NT_STATUS_IS_OK(nt_status)) {
275 /* select the sub context */
276 nt_status = gensec_start_mech_by_ops(spnego_state->sub_sec_security,
278 if (!NT_STATUS_IS_OK(nt_status)) {
284 DEBUG(1, ("Failed to parse SPNEGO request\n"));
285 return NT_STATUS_INVALID_PARAMETER;
288 static NTSTATUS gensec_spnego_create_negTokenInit_start(
289 struct gensec_security *gensec_security,
290 struct spnego_state *spnego_state,
291 struct spnego_neg_state *n,
292 struct spnego_data *spnego_in,
293 TALLOC_CTX *in_mem_ctx,
297 n->mech_types = gensec_security_oids(gensec_security, n,
299 if (n->mech_types == NULL) {
300 DBG_WARNING("gensec_security_oids() failed\n");
301 return NT_STATUS_NO_MEMORY;
305 n->all_sec = gensec_security_by_oid_list(gensec_security,
308 if (n->all_sec == NULL) {
309 DBG_WARNING("gensec_security_by_oid_list() failed\n");
310 return NT_STATUS_NO_MEMORY;
313 return n->ops->step_fn(gensec_security, spnego_state, n,
314 spnego_in, NT_STATUS_OK, in_mem_ctx, in_next);
317 static NTSTATUS gensec_spnego_create_negTokenInit_step(
318 struct gensec_security *gensec_security,
319 struct spnego_state *spnego_state,
320 struct spnego_neg_state *n,
321 struct spnego_data *spnego_in,
322 NTSTATUS last_status,
323 TALLOC_CTX *in_mem_ctx,
326 if (!NT_STATUS_IS_OK(last_status)) {
327 const struct gensec_security_ops_wrapper *cur_sec =
328 &n->all_sec[n->all_idx];
329 const struct gensec_security_ops_wrapper *next_sec = NULL;
330 const char *next = NULL;
331 const char *principal = NULL;
332 int dbg_level = DBGLVL_WARNING;
333 NTSTATUS status = last_status;
335 if (cur_sec[1].op != NULL) {
336 next_sec = &cur_sec[1];
339 if (next_sec != NULL) {
340 next = next_sec->op->name;
341 dbg_level = DBGLVL_NOTICE;
344 if (gensec_security->target.principal != NULL) {
345 principal = gensec_security->target.principal;
346 } else if (gensec_security->target.service != NULL &&
347 gensec_security->target.hostname != NULL)
349 principal = talloc_asprintf(spnego_state->sub_sec_security,
351 gensec_security->target.service,
352 gensec_security->target.hostname);
354 principal = gensec_security->target.hostname;
357 DBG_PREFIX(dbg_level, (
358 "%s: creating NEG_TOKEN_INIT for %s failed "
359 "(next[%s]): %s\n", cur_sec->op->name,
360 principal, next, nt_errstr(status)));
364 * A hard error without a possible fallback.
370 * Pretend we never started it
372 gensec_spnego_reset_sub_sec(spnego_state);
375 * And try the next one...
380 for (; n->all_sec[n->all_idx].op != NULL; n->all_idx++) {
381 const struct gensec_security_ops_wrapper *cur_sec =
382 &n->all_sec[n->all_idx];
385 status = gensec_subcontext_start(spnego_state,
387 &spnego_state->sub_sec_security);
388 if (!NT_STATUS_IS_OK(status)) {
392 /* select the sub context */
393 status = gensec_start_mech_by_ops(spnego_state->sub_sec_security,
395 if (!NT_STATUS_IS_OK(status)) {
396 gensec_spnego_reset_sub_sec(spnego_state);
400 /* In the client, try and produce the first (optimistic) packet */
401 if (spnego_state->state_position == SPNEGO_CLIENT_START) {
402 *in_next = data_blob_null;
403 return NT_STATUS_MORE_PROCESSING_REQUIRED;
406 *in_next = data_blob_null;
410 DBG_WARNING("Failed to setup SPNEGO negTokenInit request\n");
411 return NT_STATUS_INVALID_PARAMETER;
414 static NTSTATUS gensec_spnego_create_negTokenInit_finish(
415 struct gensec_security *gensec_security,
416 struct spnego_state *spnego_state,
417 struct spnego_neg_state *n,
418 struct spnego_data *spnego_in,
420 const DATA_BLOB sub_out,
421 TALLOC_CTX *out_mem_ctx,
424 const struct gensec_security_ops_wrapper *cur_sec =
425 &n->all_sec[n->all_idx];
426 struct spnego_data spnego_out;
429 spnego_out.type = SPNEGO_NEG_TOKEN_INIT;
431 n->mech_types = gensec_security_oids_from_ops_wrapped(n, cur_sec);
432 if (n->mech_types == NULL) {
433 DBG_WARNING("gensec_security_oids_from_ops_wrapped() failed\n");
434 return NT_STATUS_NO_MEMORY;
437 ok = spnego_write_mech_types(spnego_state,
439 &spnego_state->mech_types);
441 DBG_ERR("Failed to write mechTypes\n");
442 return NT_STATUS_NO_MEMORY;
445 /* List the remaining mechs as options */
446 spnego_out.negTokenInit.mechTypes = n->mech_types;
447 spnego_out.negTokenInit.reqFlags = data_blob_null;
448 spnego_out.negTokenInit.reqFlagsPadding = 0;
450 if (spnego_state->state_position == SPNEGO_SERVER_START) {
451 spnego_out.negTokenInit.mechListMIC
452 = data_blob_string_const(ADS_IGNORE_PRINCIPAL);
454 spnego_out.negTokenInit.mechListMIC = data_blob_null;
457 spnego_out.negTokenInit.mechToken = sub_out;
459 if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
460 DBG_ERR("Failed to write NEG_TOKEN_INIT\n");
461 return NT_STATUS_INVALID_PARAMETER;
465 * Note that 'cur_sec' is temporary memory, but
466 * cur_sec->oid points to a const string in the
467 * backends gensec_security_ops structure.
469 spnego_state->neg_oid = cur_sec->oid;
472 if (spnego_state->state_position == SPNEGO_SERVER_START) {
473 spnego_state->state_position = SPNEGO_SERVER_START;
474 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT;
476 spnego_state->state_position = SPNEGO_CLIENT_TARG;
477 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
480 return NT_STATUS_MORE_PROCESSING_REQUIRED;
483 static const struct spnego_neg_ops gensec_spnego_create_negTokenInit_ops = {
484 .name = "create_negTokenInit",
485 .start_fn = gensec_spnego_create_negTokenInit_start,
486 .step_fn = gensec_spnego_create_negTokenInit_step,
487 .finish_fn = gensec_spnego_create_negTokenInit_finish,
490 static NTSTATUS gensec_spnego_client_negTokenInit_start(
491 struct gensec_security *gensec_security,
492 struct spnego_state *spnego_state,
493 struct spnego_neg_state *n,
494 struct spnego_data *spnego_in,
495 TALLOC_CTX *in_mem_ctx,
498 const char *tp = NULL;
500 /* The server offers a list of mechanisms */
502 tp = spnego_in->negTokenInit.targetPrincipal;
503 if (tp != NULL && strcmp(tp, ADS_IGNORE_PRINCIPAL) != 0) {
504 DBG_INFO("Server claims it's principal name is %s\n", tp);
505 if (lpcfg_client_use_spnego_principal(gensec_security->settings->lp_ctx)) {
506 gensec_set_target_principal(gensec_security, tp);
511 n->mech_types = spnego_in->negTokenInit.mechTypes;
512 if (n->mech_types == NULL) {
513 return NT_STATUS_INVALID_PARAMETER;
517 n->all_sec = gensec_security_by_oid_list(gensec_security,
520 if (n->all_sec == NULL) {
521 DBG_WARNING("gensec_security_by_oid_list() failed\n");
522 return NT_STATUS_INVALID_PARAMETER;
525 return n->ops->step_fn(gensec_security, spnego_state, n,
526 spnego_in, NT_STATUS_OK, in_mem_ctx, in_next);
529 static NTSTATUS gensec_spnego_client_negTokenInit_step(
530 struct gensec_security *gensec_security,
531 struct spnego_state *spnego_state,
532 struct spnego_neg_state *n,
533 struct spnego_data *spnego_in,
534 NTSTATUS last_status,
535 TALLOC_CTX *in_mem_ctx,
538 if (!NT_STATUS_IS_OK(last_status)) {
539 const struct gensec_security_ops_wrapper *cur_sec =
540 &n->all_sec[n->all_idx];
541 const struct gensec_security_ops_wrapper *next_sec = NULL;
542 const char *next = NULL;
543 const char *principal = NULL;
544 int dbg_level = DBGLVL_WARNING;
545 bool allow_fallback = false;
546 NTSTATUS status = last_status;
548 if (cur_sec[1].op != NULL) {
549 next_sec = &cur_sec[1];
553 * it is likely that a NULL input token will
554 * not be liked by most server mechs, but if
555 * we are in the client, we want the first
556 * update packet to be able to abort the use
559 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
560 NT_STATUS_EQUAL(status, NT_STATUS_NO_LOGON_SERVERS) ||
561 NT_STATUS_EQUAL(status, NT_STATUS_TIME_DIFFERENCE_AT_DC) ||
562 NT_STATUS_EQUAL(status, NT_STATUS_CANT_ACCESS_DOMAIN_INFO))
564 allow_fallback = true;
567 if (allow_fallback && next_sec != NULL) {
568 next = next_sec->op->name;
569 dbg_level = DBGLVL_NOTICE;
572 if (gensec_security->target.principal != NULL) {
573 principal = gensec_security->target.principal;
574 } else if (gensec_security->target.service != NULL &&
575 gensec_security->target.hostname != NULL)
577 principal = talloc_asprintf(spnego_state->sub_sec_security,
579 gensec_security->target.service,
580 gensec_security->target.hostname);
582 principal = gensec_security->target.hostname;
585 DBG_PREFIX(dbg_level, (
586 "%s: creating NEG_TOKEN_INIT for %s failed "
587 "(next[%s]): %s\n", cur_sec->op->name,
588 principal, next, nt_errstr(status)));
592 * A hard error without a possible fallback.
598 * Pretend we never started it.
600 gensec_spnego_reset_sub_sec(spnego_state);
603 * And try the next one...
608 for (; n->all_sec[n->all_idx].op != NULL; n->all_idx++) {
609 const struct gensec_security_ops_wrapper *cur_sec =
610 &n->all_sec[n->all_idx];
613 status = gensec_subcontext_start(spnego_state,
615 &spnego_state->sub_sec_security);
616 if (!NT_STATUS_IS_OK(status)) {
620 /* select the sub context */
621 status = gensec_start_mech_by_ops(spnego_state->sub_sec_security,
623 if (!NT_STATUS_IS_OK(status)) {
624 gensec_spnego_reset_sub_sec(spnego_state);
629 * Note that 'cur_sec' is temporary memory, but
630 * cur_sec->oid points to a const string in the
631 * backends gensec_security_ops structure.
633 spnego_state->neg_oid = cur_sec->oid;
636 * As client we don't use an optimistic token from the server.
637 * But try to produce one for the server.
639 *in_next = data_blob_null;
640 return NT_STATUS_MORE_PROCESSING_REQUIRED;
643 DBG_WARNING("Could not find a suitable mechtype in NEG_TOKEN_INIT\n");
644 return NT_STATUS_INVALID_PARAMETER;
647 static NTSTATUS gensec_spnego_client_negTokenInit_finish(
648 struct gensec_security *gensec_security,
649 struct spnego_state *spnego_state,
650 struct spnego_neg_state *n,
651 struct spnego_data *spnego_in,
653 const DATA_BLOB sub_out,
654 TALLOC_CTX *out_mem_ctx,
657 struct spnego_data spnego_out;
658 const char *my_mechs[] = {NULL, NULL};
661 my_mechs[0] = spnego_state->neg_oid;
663 spnego_out.type = SPNEGO_NEG_TOKEN_INIT;
664 spnego_out.negTokenInit.mechTypes = my_mechs;
665 spnego_out.negTokenInit.reqFlags = data_blob_null;
666 spnego_out.negTokenInit.reqFlagsPadding = 0;
667 spnego_out.negTokenInit.mechListMIC = data_blob_null;
668 spnego_out.negTokenInit.mechToken = sub_out;
670 if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
671 DBG_ERR("Failed to write SPNEGO reply to NEG_TOKEN_INIT\n");
672 return NT_STATUS_INVALID_PARAMETER;
675 ok = spnego_write_mech_types(spnego_state,
677 &spnego_state->mech_types);
679 DBG_ERR("failed to write mechTypes\n");
680 return NT_STATUS_NO_MEMORY;
684 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
685 spnego_state->state_position = SPNEGO_CLIENT_TARG;
687 return NT_STATUS_MORE_PROCESSING_REQUIRED;
690 static const struct spnego_neg_ops gensec_spnego_client_negTokenInit_ops = {
691 .name = "client_negTokenInit",
692 .start_fn = gensec_spnego_client_negTokenInit_start,
693 .step_fn = gensec_spnego_client_negTokenInit_step,
694 .finish_fn = gensec_spnego_client_negTokenInit_finish,
697 static NTSTATUS gensec_spnego_client_negTokenTarg_start(
698 struct gensec_security *gensec_security,
699 struct spnego_state *spnego_state,
700 struct spnego_neg_state *n,
701 struct spnego_data *spnego_in,
702 TALLOC_CTX *in_mem_ctx,
705 struct spnego_negTokenTarg *ta = &spnego_in->negTokenTarg;
708 spnego_state->num_targs++;
710 if (ta->negResult == SPNEGO_REJECT) {
711 return NT_STATUS_LOGON_FAILURE;
714 if (ta->negResult == SPNEGO_REQUEST_MIC) {
715 spnego_state->mic_requested = true;
718 if (ta->mechListMIC.length > 0) {
719 DATA_BLOB *m = &ta->mechListMIC;
720 const DATA_BLOB *r = &ta->responseToken;
723 * Windows 2000 has a bug, it repeats the
724 * responseToken in the mechListMIC field.
726 if (m->length == r->length) {
729 cmp = memcmp(m->data, r->data, m->length);
736 /* Server didn't like our choice of mech, and chose something else */
737 if (((ta->negResult == SPNEGO_ACCEPT_INCOMPLETE) ||
738 (ta->negResult == SPNEGO_REQUEST_MIC)) &&
739 ta->supportedMech != NULL &&
740 strcmp(ta->supportedMech, spnego_state->neg_oid) != 0)
742 const char *client_mech = NULL;
743 const char *client_oid = NULL;
744 const char *server_mech = NULL;
745 const char *server_oid = NULL;
747 client_mech = gensec_get_name_by_oid(gensec_security,
748 spnego_state->neg_oid);
749 client_oid = spnego_state->neg_oid;
750 server_mech = gensec_get_name_by_oid(gensec_security,
752 server_oid = ta->supportedMech;
754 DBG_NOTICE("client preferred mech (%s[%s]) not accepted, "
755 "server wants: %s[%s]\n",
756 client_mech, client_oid, server_mech, server_oid);
758 spnego_state->downgraded = true;
759 gensec_spnego_reset_sub_sec(spnego_state);
761 status = gensec_subcontext_start(spnego_state,
763 &spnego_state->sub_sec_security);
764 if (!NT_STATUS_IS_OK(status)) {
768 /* select the sub context */
769 status = gensec_start_mech_by_oid(spnego_state->sub_sec_security,
771 if (!NT_STATUS_IS_OK(status)) {
775 spnego_state->neg_oid = talloc_strdup(spnego_state,
777 if (spnego_state->neg_oid == NULL) {
778 return NT_STATUS_NO_MEMORY;
782 if (ta->mechListMIC.length > 0) {
783 if (spnego_state->sub_sec_ready) {
784 spnego_state->needs_mic_check = true;
788 if (spnego_state->needs_mic_check) {
789 if (ta->responseToken.length != 0) {
790 DBG_WARNING("non empty response token not expected\n");
791 return NT_STATUS_INVALID_PARAMETER;
794 if (ta->mechListMIC.length == 0
795 && spnego_state->may_skip_mic_check) {
797 * In this case we don't require
798 * a mechListMIC from the server.
800 * This works around bugs in the Azure
801 * and Apple spnego implementations.
804 * https://bugzilla.samba.org/show_bug.cgi?id=11994
806 spnego_state->needs_mic_check = false;
810 status = gensec_check_packet(spnego_state->sub_sec_security,
811 spnego_state->mech_types.data,
812 spnego_state->mech_types.length,
813 spnego_state->mech_types.data,
814 spnego_state->mech_types.length,
816 if (!NT_STATUS_IS_OK(status)) {
817 DBG_WARNING("failed to verify mechListMIC: %s\n",
821 spnego_state->needs_mic_check = false;
822 spnego_state->done_mic_check = true;
826 if (!spnego_state->sub_sec_ready) {
827 *in_next = ta->responseToken;
828 return NT_STATUS_MORE_PROCESSING_REQUIRED;
834 static NTSTATUS gensec_spnego_client_negTokenTarg_step(
835 struct gensec_security *gensec_security,
836 struct spnego_state *spnego_state,
837 struct spnego_neg_state *n,
838 struct spnego_data *spnego_in,
839 NTSTATUS last_status,
840 TALLOC_CTX *in_mem_ctx,
843 if (GENSEC_UPDATE_IS_NTERROR(last_status)) {
844 DBG_WARNING("SPNEGO(%s) login failed: %s\n",
845 spnego_state->sub_sec_security->ops->name,
846 nt_errstr(last_status));
851 * This should never be reached!
852 * The step function is only called on errors!
854 smb_panic(__location__);
855 return NT_STATUS_INTERNAL_ERROR;
858 static NTSTATUS gensec_spnego_client_negTokenTarg_finish(
859 struct gensec_security *gensec_security,
860 struct spnego_state *spnego_state,
861 struct spnego_neg_state *n,
862 struct spnego_data *spnego_in,
864 const DATA_BLOB sub_out,
865 TALLOC_CTX *out_mem_ctx,
868 const struct spnego_negTokenTarg *ta =
869 &spnego_in->negTokenTarg;
870 DATA_BLOB mech_list_mic = data_blob_null;
872 struct spnego_data spnego_out;
876 if (!spnego_state->sub_sec_ready) {
878 * We're not yet ready to deal with signatures.
880 goto client_response;
883 if (spnego_state->done_mic_check) {
885 * We already checked the mic,
886 * either the in last round here
887 * in gensec_spnego_client_negTokenTarg_finish()
888 * or during this round in
889 * gensec_spnego_client_negTokenTarg_start().
891 * Both cases we're sure we don't have to
892 * call gensec_sign_packet().
894 goto client_response;
897 if (spnego_state->may_skip_mic_check) {
899 * This can only be set during
900 * the last round here in
901 * gensec_spnego_client_negTokenTarg_finish()
902 * below. And during this round
903 * we already passed the checks in
904 * gensec_spnego_client_negTokenTarg_start().
906 * So we need to skip to deal with
907 * any signatures now.
909 goto client_response;
912 if (!spnego_state->done_mic_check) {
913 bool have_sign = true;
914 bool new_spnego = false;
916 have_sign = gensec_have_feature(spnego_state->sub_sec_security,
917 GENSEC_FEATURE_SIGN);
918 if (spnego_state->simulate_w2k) {
921 new_spnego = gensec_have_feature(spnego_state->sub_sec_security,
922 GENSEC_FEATURE_NEW_SPNEGO);
924 switch (ta->negResult) {
925 case SPNEGO_ACCEPT_COMPLETED:
926 case SPNEGO_NONE_RESULT:
927 if (spnego_state->num_targs == 1) {
929 * the first exchange doesn't require
937 case SPNEGO_ACCEPT_INCOMPLETE:
938 if (ta->mechListMIC.length > 0) {
943 if (spnego_state->downgraded) {
945 * A downgrade should be protected if
952 * The caller may just asked for
953 * GENSEC_FEATURE_SESSION_KEY, this
954 * is only reflected in the want_features.
957 * gensec_have_features(GENSEC_FEATURE_SIGN)
960 if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
963 if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
967 * Here we're sure our preferred mech was
968 * selected by the server and our caller doesn't
969 * need GENSEC_FEATURE_SIGN nor
970 * GENSEC_FEATURE_SEAL support.
972 * In this case we don't require
973 * a mechListMIC from the server.
975 * This works around bugs in the Azure
976 * and Apple spnego implementations.
979 * https://bugzilla.samba.org/show_bug.cgi?id=11994
981 spnego_state->may_skip_mic_check = true;
984 case SPNEGO_REQUEST_MIC:
985 if (ta->mechListMIC.length > 0) {
993 if (spnego_state->mic_requested) {
999 if (have_sign && new_spnego) {
1000 spnego_state->needs_mic_check = true;
1001 spnego_state->needs_mic_sign = true;
1005 if (ta->mechListMIC.length > 0) {
1006 status = gensec_check_packet(spnego_state->sub_sec_security,
1007 spnego_state->mech_types.data,
1008 spnego_state->mech_types.length,
1009 spnego_state->mech_types.data,
1010 spnego_state->mech_types.length,
1012 if (!NT_STATUS_IS_OK(status)) {
1013 DBG_WARNING("failed to verify mechListMIC: %s\n",
1017 spnego_state->needs_mic_check = false;
1018 spnego_state->done_mic_check = true;
1021 if (spnego_state->needs_mic_sign) {
1022 status = gensec_sign_packet(spnego_state->sub_sec_security,
1024 spnego_state->mech_types.data,
1025 spnego_state->mech_types.length,
1026 spnego_state->mech_types.data,
1027 spnego_state->mech_types.length,
1029 if (!NT_STATUS_IS_OK(status)) {
1030 DBG_WARNING("failed to sign mechListMIC: %s\n",
1034 spnego_state->needs_mic_sign = false;
1038 if (sub_out.length == 0 && mech_list_mic.length == 0) {
1039 *out = data_blob_null;
1041 if (!spnego_state->sub_sec_ready) {
1042 /* somethings wrong here... */
1043 DBG_ERR("gensec_update not ready without output\n");
1044 return NT_STATUS_INTERNAL_ERROR;
1047 if (ta->negResult != SPNEGO_ACCEPT_COMPLETED) {
1048 /* unless of course it did not accept */
1049 DBG_WARNING("gensec_update ok but not accepted\n");
1050 return NT_STATUS_INVALID_PARAMETER;
1053 if (!spnego_state->needs_mic_check) {
1054 spnego_state->state_position = SPNEGO_DONE;
1055 return NT_STATUS_OK;
1060 spnego_out.type = SPNEGO_NEG_TOKEN_TARG;
1061 spnego_out.negTokenTarg.negResult = SPNEGO_NONE_RESULT;
1062 spnego_out.negTokenTarg.supportedMech = NULL;
1063 spnego_out.negTokenTarg.responseToken = sub_out;
1064 spnego_out.negTokenTarg.mechListMIC = mech_list_mic;
1066 if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
1067 DBG_WARNING("Failed to write NEG_TOKEN_TARG\n");
1068 return NT_STATUS_INVALID_PARAMETER;
1071 spnego_state->num_targs++;
1073 /* set next state */
1074 spnego_state->state_position = SPNEGO_CLIENT_TARG;
1075 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
1077 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1080 static const struct spnego_neg_ops gensec_spnego_client_negTokenTarg_ops = {
1081 .name = "client_negTokenTarg",
1082 .start_fn = gensec_spnego_client_negTokenTarg_start,
1083 .step_fn = gensec_spnego_client_negTokenTarg_step,
1084 .finish_fn = gensec_spnego_client_negTokenTarg_finish,
1087 /** create a server negTokenTarg
1089 * This is the case, where the client is the first one who sends data
1092 static NTSTATUS gensec_spnego_server_response(struct spnego_state *spnego_state,
1093 TALLOC_CTX *out_mem_ctx,
1095 const DATA_BLOB unwrapped_out,
1096 DATA_BLOB mech_list_mic,
1099 struct spnego_data spnego_out;
1102 spnego_out.type = SPNEGO_NEG_TOKEN_TARG;
1103 spnego_out.negTokenTarg.responseToken = unwrapped_out;
1104 spnego_out.negTokenTarg.mechListMIC = mech_list_mic;
1105 spnego_out.negTokenTarg.supportedMech = NULL;
1107 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1108 spnego_out.negTokenTarg.supportedMech = spnego_state->neg_oid;
1109 if (spnego_state->mic_requested) {
1110 spnego_out.negTokenTarg.negResult = SPNEGO_REQUEST_MIC;
1111 spnego_state->mic_requested = false;
1113 spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
1115 spnego_state->state_position = SPNEGO_SERVER_TARG;
1116 } else if (NT_STATUS_IS_OK(nt_status)) {
1117 if (unwrapped_out.data) {
1118 spnego_out.negTokenTarg.supportedMech = spnego_state->neg_oid;
1120 spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED;
1121 spnego_state->state_position = SPNEGO_DONE;
1124 if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
1125 DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n"));
1126 return NT_STATUS_INVALID_PARAMETER;
1129 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
1130 spnego_state->num_targs++;
1135 static NTSTATUS gensec_spnego_server_negTokenInit_start(
1136 struct gensec_security *gensec_security,
1137 struct spnego_state *spnego_state,
1138 struct spnego_neg_state *n,
1139 struct spnego_data *spnego_in,
1140 TALLOC_CTX *in_mem_ctx,
1146 n->mech_types = spnego_in->negTokenInit.mechTypes;
1147 if (n->mech_types == NULL) {
1148 return NT_STATUS_INVALID_PARAMETER;
1152 n->all_sec = gensec_security_by_oid_list(gensec_security,
1155 if (n->all_sec == NULL) {
1156 DBG_WARNING("gensec_security_by_oid_list() failed\n");
1157 return NT_STATUS_INVALID_PARAMETER;
1160 ok = spnego_write_mech_types(spnego_state,
1162 &spnego_state->mech_types);
1164 DBG_ERR("Failed to write mechTypes\n");
1165 return NT_STATUS_NO_MEMORY;
1168 return n->ops->step_fn(gensec_security, spnego_state, n,
1169 spnego_in, NT_STATUS_OK, in_mem_ctx, in_next);
1172 static NTSTATUS gensec_spnego_server_negTokenInit_step(
1173 struct gensec_security *gensec_security,
1174 struct spnego_state *spnego_state,
1175 struct spnego_neg_state *n,
1176 struct spnego_data *spnego_in,
1177 NTSTATUS last_status,
1178 TALLOC_CTX *in_mem_ctx,
1181 if (!NT_STATUS_IS_OK(last_status)) {
1182 const struct gensec_security_ops_wrapper *cur_sec =
1183 &n->all_sec[n->all_idx];
1184 const char *next_mech = n->mech_types[n->mech_idx+1];
1185 const struct gensec_security_ops_wrapper *next_sec = NULL;
1186 const char *next = NULL;
1187 int dbg_level = DBGLVL_WARNING;
1188 bool allow_fallback = false;
1189 NTSTATUS status = last_status;
1192 for (i = 0; next_mech != NULL && n->all_sec[i].op != NULL; i++) {
1193 if (strcmp(next_mech, n->all_sec[i].oid) != 0) {
1197 next_sec = &n->all_sec[i];
1201 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
1202 NT_STATUS_EQUAL(status, NT_STATUS_CANT_ACCESS_DOMAIN_INFO))
1204 allow_fallback = true;
1207 if (allow_fallback && next_sec != NULL) {
1208 next = next_sec->op->name;
1209 dbg_level = DBGLVL_NOTICE;
1212 DBG_PREFIX(dbg_level, (
1213 "%s: parsing NEG_TOKEN_INIT content failed "
1214 "(next[%s]): %s\n", cur_sec->op->name,
1215 next, nt_errstr(status)));
1219 * A hard error without a possible fallback.
1225 * Pretend we never started it
1227 gensec_spnego_reset_sub_sec(spnego_state);
1230 * And try the next one, based on the clients
1237 * we always reset all_idx here, as the negotiation is
1238 * done via mech_idx!
1242 for (; n->mech_types[n->mech_idx] != NULL; n->mech_idx++) {
1243 const char *cur_mech = n->mech_types[n->mech_idx];
1244 const struct gensec_security_ops_wrapper *cur_sec = NULL;
1246 DATA_BLOB sub_in = data_blob_null;
1249 for (i = 0; n->all_sec[i].op != NULL; i++) {
1250 if (strcmp(cur_mech, n->all_sec[i].oid) != 0) {
1254 cur_sec = &n->all_sec[i];
1259 if (cur_sec == NULL) {
1263 status = gensec_subcontext_start(spnego_state,
1265 &spnego_state->sub_sec_security);
1266 if (!NT_STATUS_IS_OK(status)) {
1270 /* select the sub context */
1271 status = gensec_start_mech_by_ops(spnego_state->sub_sec_security,
1273 if (!NT_STATUS_IS_OK(status)) {
1275 * Pretend we never started it
1277 gensec_spnego_reset_sub_sec(spnego_state);
1281 if (n->mech_idx == 0) {
1283 * We can use the optimistic token.
1285 sub_in = spnego_in->negTokenInit.mechToken;
1288 * Indicate the downgrade and request a
1291 spnego_state->downgraded = true;
1292 spnego_state->mic_requested = true;
1296 * Note that 'cur_sec' is temporary memory, but
1297 * cur_sec->oid points to a const string in the
1298 * backends gensec_security_ops structure.
1300 spnego_state->neg_oid = cur_sec->oid;
1302 /* we need some content from the mech */
1304 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1307 DBG_WARNING("Could not find a suitable mechtype in NEG_TOKEN_INIT\n");
1308 return NT_STATUS_INVALID_PARAMETER;
1311 static NTSTATUS gensec_spnego_server_negTokenInit_finish(
1312 struct gensec_security *gensec_security,
1313 struct spnego_state *spnego_state,
1314 struct spnego_neg_state *n,
1315 struct spnego_data *spnego_in,
1316 NTSTATUS sub_status,
1317 const DATA_BLOB sub_out,
1318 TALLOC_CTX *out_mem_ctx,
1321 DATA_BLOB mech_list_mic = data_blob_null;
1323 if (spnego_state->simulate_w2k) {
1325 * Windows 2000 returns the unwrapped token
1326 * also in the mech_list_mic field.
1328 * In order to verify our client code,
1329 * we need a way to have a server with this
1332 mech_list_mic = sub_out;
1335 return gensec_spnego_server_response(spnego_state,
1343 static const struct spnego_neg_ops gensec_spnego_server_negTokenInit_ops = {
1344 .name = "server_negTokenInit",
1345 .start_fn = gensec_spnego_server_negTokenInit_start,
1346 .step_fn = gensec_spnego_server_negTokenInit_step,
1347 .finish_fn = gensec_spnego_server_negTokenInit_finish,
1350 static NTSTATUS gensec_spnego_server_negTokenTarg_start(
1351 struct gensec_security *gensec_security,
1352 struct spnego_state *spnego_state,
1353 struct spnego_neg_state *n,
1354 struct spnego_data *spnego_in,
1355 TALLOC_CTX *in_mem_ctx,
1358 const struct spnego_negTokenTarg *ta = &spnego_in->negTokenTarg;
1361 spnego_state->num_targs++;
1363 if (spnego_state->sub_sec_security == NULL) {
1364 DBG_ERR("SPNEGO: Did not setup a mech in NEG_TOKEN_INIT\n");
1365 return NT_STATUS_INVALID_PARAMETER;
1368 if (spnego_state->needs_mic_check) {
1369 if (ta->responseToken.length != 0) {
1370 DBG_WARNING("non empty response token not expected\n");
1371 return NT_STATUS_INVALID_PARAMETER;
1374 status = gensec_check_packet(spnego_state->sub_sec_security,
1375 spnego_state->mech_types.data,
1376 spnego_state->mech_types.length,
1377 spnego_state->mech_types.data,
1378 spnego_state->mech_types.length,
1380 if (!NT_STATUS_IS_OK(status)) {
1381 DBG_WARNING("failed to verify mechListMIC: %s\n",
1386 spnego_state->needs_mic_check = false;
1387 spnego_state->done_mic_check = true;
1388 return NT_STATUS_OK;
1391 if (!spnego_state->sub_sec_ready) {
1392 *in_next = ta->responseToken;
1393 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1396 return NT_STATUS_OK;
1399 static NTSTATUS gensec_spnego_server_negTokenTarg_step(
1400 struct gensec_security *gensec_security,
1401 struct spnego_state *spnego_state,
1402 struct spnego_neg_state *n,
1403 struct spnego_data *spnego_in,
1404 NTSTATUS last_status,
1405 TALLOC_CTX *in_mem_ctx,
1408 if (GENSEC_UPDATE_IS_NTERROR(last_status)) {
1409 DBG_NOTICE("SPNEGO(%s) login failed: %s\n",
1410 spnego_state->sub_sec_security->ops->name,
1411 nt_errstr(last_status));
1416 * This should never be reached!
1417 * The step function is only called on errors!
1419 smb_panic(__location__);
1420 return NT_STATUS_INTERNAL_ERROR;
1423 static NTSTATUS gensec_spnego_server_negTokenTarg_finish(
1424 struct gensec_security *gensec_security,
1425 struct spnego_state *spnego_state,
1426 struct spnego_neg_state *n,
1427 struct spnego_data *spnego_in,
1428 NTSTATUS sub_status,
1429 const DATA_BLOB sub_out,
1430 TALLOC_CTX *out_mem_ctx,
1433 const struct spnego_negTokenTarg *ta = &spnego_in->negTokenTarg;
1434 DATA_BLOB mech_list_mic = data_blob_null;
1436 bool have_sign = true;
1437 bool new_spnego = false;
1439 status = sub_status;
1441 if (!spnego_state->sub_sec_ready) {
1443 * We're not yet ready to deal with signatures.
1445 goto server_response;
1448 if (spnego_state->done_mic_check) {
1450 * We already checked the mic,
1451 * either the in last round here
1452 * in gensec_spnego_server_negTokenTarg_finish()
1453 * or during this round in
1454 * gensec_spnego_server_negTokenTarg_start().
1456 * Both cases we're sure we don't have to
1457 * call gensec_sign_packet().
1459 goto server_response;
1462 have_sign = gensec_have_feature(spnego_state->sub_sec_security,
1463 GENSEC_FEATURE_SIGN);
1464 if (spnego_state->simulate_w2k) {
1467 new_spnego = gensec_have_feature(spnego_state->sub_sec_security,
1468 GENSEC_FEATURE_NEW_SPNEGO);
1469 if (ta->mechListMIC.length > 0) {
1473 if (have_sign && new_spnego) {
1474 spnego_state->needs_mic_check = true;
1475 spnego_state->needs_mic_sign = true;
1478 if (have_sign && ta->mechListMIC.length > 0) {
1479 status = gensec_check_packet(spnego_state->sub_sec_security,
1480 spnego_state->mech_types.data,
1481 spnego_state->mech_types.length,
1482 spnego_state->mech_types.data,
1483 spnego_state->mech_types.length,
1485 if (!NT_STATUS_IS_OK(status)) {
1486 DBG_WARNING("failed to verify mechListMIC: %s\n",
1491 spnego_state->needs_mic_check = false;
1492 spnego_state->done_mic_check = true;
1495 if (spnego_state->needs_mic_sign) {
1496 status = gensec_sign_packet(spnego_state->sub_sec_security,
1498 spnego_state->mech_types.data,
1499 spnego_state->mech_types.length,
1500 spnego_state->mech_types.data,
1501 spnego_state->mech_types.length,
1503 if (!NT_STATUS_IS_OK(status)) {
1504 DBG_WARNING("failed to sign mechListMIC: %s\n",
1508 spnego_state->needs_mic_sign = false;
1511 if (spnego_state->needs_mic_check) {
1512 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1516 return gensec_spnego_server_response(spnego_state,
1524 static const struct spnego_neg_ops gensec_spnego_server_negTokenTarg_ops = {
1525 .name = "server_negTokenTarg",
1526 .start_fn = gensec_spnego_server_negTokenTarg_start,
1527 .step_fn = gensec_spnego_server_negTokenTarg_step,
1528 .finish_fn = gensec_spnego_server_negTokenTarg_finish,
1531 struct gensec_spnego_update_state {
1532 struct tevent_context *ev;
1533 struct gensec_security *gensec;
1534 struct spnego_state *spnego;
1537 struct spnego_data _spnego_in;
1538 struct spnego_data *spnego_in;
1547 struct spnego_neg_state *n;
1553 static void gensec_spnego_update_cleanup(struct tevent_req *req,
1554 enum tevent_req_state req_state)
1556 struct gensec_spnego_update_state *state =
1557 tevent_req_data(req,
1558 struct gensec_spnego_update_state);
1560 switch (req_state) {
1561 case TEVENT_REQ_USER_ERROR:
1562 case TEVENT_REQ_TIMED_OUT:
1563 case TEVENT_REQ_NO_MEMORY:
1565 * A fatal error, further updates are not allowed.
1567 state->spnego->state_position = SPNEGO_DONE;
1574 static NTSTATUS gensec_spnego_update_in(struct gensec_security *gensec_security,
1575 const DATA_BLOB in, TALLOC_CTX *mem_ctx,
1576 DATA_BLOB *full_in);
1577 static void gensec_spnego_update_pre(struct tevent_req *req);
1578 static void gensec_spnego_update_done(struct tevent_req *subreq);
1579 static void gensec_spnego_update_post(struct tevent_req *req);
1580 static NTSTATUS gensec_spnego_update_out(struct gensec_security *gensec_security,
1581 TALLOC_CTX *out_mem_ctx,
1584 static struct tevent_req *gensec_spnego_update_send(TALLOC_CTX *mem_ctx,
1585 struct tevent_context *ev,
1586 struct gensec_security *gensec_security,
1589 struct spnego_state *spnego_state =
1590 talloc_get_type_abort(gensec_security->private_data,
1591 struct spnego_state);
1592 struct tevent_req *req = NULL;
1593 struct gensec_spnego_update_state *state = NULL;
1597 req = tevent_req_create(mem_ctx, &state,
1598 struct gensec_spnego_update_state);
1603 state->gensec = gensec_security;
1604 state->spnego = spnego_state;
1605 tevent_req_set_cleanup_fn(req, gensec_spnego_update_cleanup);
1607 if (spnego_state->out_frag.length > 0) {
1608 if (in.length > 0) {
1609 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1610 return tevent_req_post(req, ev);
1613 status = gensec_spnego_update_out(gensec_security,
1614 state, &state->out);
1615 if (GENSEC_UPDATE_IS_NTERROR(status)) {
1616 tevent_req_nterror(req, status);
1617 return tevent_req_post(req, ev);
1620 state->status = status;
1621 tevent_req_done(req);
1622 return tevent_req_post(req, ev);
1625 status = gensec_spnego_update_in(gensec_security, in,
1626 state, &state->full_in);
1627 state->status = status;
1628 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1629 tevent_req_done(req);
1630 return tevent_req_post(req, ev);
1632 if (tevent_req_nterror(req, status)) {
1633 return tevent_req_post(req, ev);
1636 /* Check if we got a valid SPNEGO blob... */
1638 switch (spnego_state->state_position) {
1639 case SPNEGO_FALLBACK:
1642 case SPNEGO_CLIENT_TARG:
1643 case SPNEGO_SERVER_TARG:
1644 if (state->full_in.length == 0) {
1645 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1646 return tevent_req_post(req, ev);
1650 case SPNEGO_CLIENT_START:
1651 case SPNEGO_SERVER_START:
1653 if (state->full_in.length == 0) {
1654 /* create_negTokenInit later */
1658 len = spnego_read_data(state,
1660 &state->_spnego_in);
1662 if (spnego_state->state_position != SPNEGO_SERVER_START) {
1663 DEBUG(1, ("Invalid SPNEGO request:\n"));
1664 dump_data(1, state->full_in.data,
1665 state->full_in.length);
1666 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1667 return tevent_req_post(req, ev);
1671 * This is the 'fallback' case, where we don't get
1672 * SPNEGO, and have to try all the other options (and
1673 * hope they all have a magic string they check)
1675 status = gensec_spnego_server_try_fallback(gensec_security,
1679 if (tevent_req_nterror(req, status)) {
1680 return tevent_req_post(req, ev);
1684 * We'll continue with SPNEGO_FALLBACK below...
1688 state->spnego_in = &state->_spnego_in;
1690 /* OK, so it's real SPNEGO, check the packet's the one we expect */
1691 if (state->spnego_in->type != spnego_state->expected_packet) {
1692 DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n",
1693 state->spnego_in->type,
1694 spnego_state->expected_packet));
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);
1704 smb_panic(__location__);
1708 gensec_spnego_update_pre(req);
1709 if (!tevent_req_is_in_progress(req)) {
1710 return tevent_req_post(req, ev);
1713 if (state->sub.needed) {
1714 struct tevent_req *subreq = NULL;
1717 * We may need one more roundtrip...
1719 subreq = gensec_update_send(state, state->ev,
1720 spnego_state->sub_sec_security,
1722 if (tevent_req_nomem(subreq, req)) {
1723 return tevent_req_post(req, ev);
1725 tevent_req_set_callback(subreq,
1726 gensec_spnego_update_done,
1728 state->sub.needed = false;
1732 gensec_spnego_update_post(req);
1733 if (!tevent_req_is_in_progress(req)) {
1734 return tevent_req_post(req, ev);
1740 static NTSTATUS gensec_spnego_update_in(struct gensec_security *gensec_security,
1741 const DATA_BLOB in, TALLOC_CTX *mem_ctx,
1744 struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
1748 *full_in = data_blob_null;
1750 switch (spnego_state->state_position) {
1751 case SPNEGO_FALLBACK:
1753 spnego_state->in_needed = 0;
1754 return NT_STATUS_OK;
1756 case SPNEGO_CLIENT_START:
1757 case SPNEGO_CLIENT_TARG:
1758 case SPNEGO_SERVER_START:
1759 case SPNEGO_SERVER_TARG:
1764 return NT_STATUS_INVALID_PARAMETER;
1767 if (spnego_state->in_needed == 0) {
1772 * try to work out the size of the full
1773 * input token, it might be fragmented
1775 ret = asn1_peek_full_tag(in, ASN1_APPLICATION(0), &size);
1776 if ((ret != 0) && (ret != EAGAIN)) {
1777 ret = asn1_peek_full_tag(in, ASN1_CONTEXT(1), &size);
1780 if ((ret == 0) || (ret == EAGAIN)) {
1781 spnego_state->in_needed = size;
1784 * If it is not an asn1 message
1785 * just call the next layer.
1787 spnego_state->in_needed = in.length;
1791 if (spnego_state->in_needed > UINT16_MAX) {
1793 * limit the incoming message to 0xFFFF
1794 * to avoid DoS attacks.
1796 return NT_STATUS_INVALID_BUFFER_SIZE;
1799 if ((spnego_state->in_needed > 0) && (in.length == 0)) {
1801 * If we reach this, we know we got at least
1802 * part of an asn1 message, getting 0 means
1803 * the remote peer wants us to spin.
1805 return NT_STATUS_INVALID_PARAMETER;
1808 expected = spnego_state->in_needed - spnego_state->in_frag.length;
1809 if (in.length > expected) {
1811 * we got more than expected
1813 return NT_STATUS_INVALID_PARAMETER;
1816 if (in.length == spnego_state->in_needed) {
1818 * if the in.length contains the full blob
1821 * Note: this implies spnego_state->in_frag.length == 0,
1822 * but we do not need to check this explicitly
1823 * because we already know that we did not get
1824 * more than expected.
1827 spnego_state->in_needed = 0;
1828 return NT_STATUS_OK;
1831 ok = data_blob_append(spnego_state, &spnego_state->in_frag,
1832 in.data, in.length);
1834 return NT_STATUS_NO_MEMORY;
1837 if (spnego_state->in_needed > spnego_state->in_frag.length) {
1838 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1841 *full_in = spnego_state->in_frag;
1842 talloc_steal(mem_ctx, full_in->data);
1843 spnego_state->in_frag = data_blob_null;
1844 spnego_state->in_needed = 0;
1845 return NT_STATUS_OK;
1848 static void gensec_spnego_update_pre(struct tevent_req *req)
1850 struct gensec_spnego_update_state *state =
1851 tevent_req_data(req,
1852 struct gensec_spnego_update_state);
1853 struct spnego_state *spnego_state = state->spnego;
1854 const struct spnego_neg_ops *ops = NULL;
1857 state->sub.needed = false;
1858 state->sub.in = data_blob_null;
1859 state->sub.status = NT_STATUS_INTERNAL_ERROR;
1860 state->sub.out = data_blob_null;
1862 if (spnego_state->state_position == SPNEGO_FALLBACK) {
1863 state->sub.in = state->full_in;
1864 state->full_in = data_blob_null;
1865 state->sub.needed = true;
1869 switch (spnego_state->state_position) {
1870 case SPNEGO_CLIENT_START:
1871 if (state->spnego_in == NULL) {
1872 /* client to produce negTokenInit */
1873 ops = &gensec_spnego_create_negTokenInit_ops;
1877 ops = &gensec_spnego_client_negTokenInit_ops;
1880 case SPNEGO_CLIENT_TARG:
1881 ops = &gensec_spnego_client_negTokenTarg_ops;
1884 case SPNEGO_SERVER_START:
1885 if (state->spnego_in == NULL) {
1886 /* server to produce negTokenInit */
1887 ops = &gensec_spnego_create_negTokenInit_ops;
1891 ops = &gensec_spnego_server_negTokenInit_ops;
1894 case SPNEGO_SERVER_TARG:
1895 ops = &gensec_spnego_server_negTokenTarg_ops;
1899 smb_panic(__location__);
1903 state->n = gensec_spnego_neg_state(state, ops);
1904 if (tevent_req_nomem(state->n, req)) {
1908 status = ops->start_fn(state->gensec, spnego_state, state->n,
1909 state->spnego_in, state, &state->sub.in);
1910 if (GENSEC_UPDATE_IS_NTERROR(status)) {
1911 tevent_req_nterror(req, status);
1915 if (NT_STATUS_IS_OK(status)) {
1917 * Call finish_fn() with an empty
1918 * blob and NT_STATUS_OK.
1920 state->sub.status = NT_STATUS_OK;
1923 * MORE_PROCESSING_REQUIRED =>
1924 * we need to call gensec_update_send().
1926 state->sub.needed = true;
1930 static void gensec_spnego_update_done(struct tevent_req *subreq)
1932 struct tevent_req *req =
1933 tevent_req_callback_data(subreq,
1935 struct gensec_spnego_update_state *state =
1936 tevent_req_data(req,
1937 struct gensec_spnego_update_state);
1938 struct spnego_state *spnego_state = state->spnego;
1940 state->sub.status = gensec_update_recv(subreq, state, &state->sub.out);
1941 TALLOC_FREE(subreq);
1942 if (NT_STATUS_IS_OK(state->sub.status)) {
1943 spnego_state->sub_sec_ready = true;
1946 gensec_spnego_update_post(req);
1949 static void gensec_spnego_update_post(struct tevent_req *req)
1951 struct gensec_spnego_update_state *state =
1952 tevent_req_data(req,
1953 struct gensec_spnego_update_state);
1954 struct spnego_state *spnego_state = state->spnego;
1955 const struct spnego_neg_ops *ops = NULL;
1958 state->sub.in = data_blob_null;
1959 state->sub.needed = false;
1961 if (spnego_state->state_position == SPNEGO_FALLBACK) {
1962 status = state->sub.status;
1963 spnego_state->out_frag = state->sub.out;
1964 talloc_steal(spnego_state, spnego_state->out_frag.data);
1965 state->sub.out = data_blob_null;
1969 ops = state->n->ops;
1971 if (GENSEC_UPDATE_IS_NTERROR(state->sub.status)) {
1975 * gensec_update_recv() returned an error,
1976 * let's see if the step_fn() want to
1977 * handle it and negotiate something else.
1980 status = ops->step_fn(state->gensec,
1987 if (GENSEC_UPDATE_IS_NTERROR(status)) {
1988 tevent_req_nterror(req, status);
1992 state->sub.out = data_blob_null;
1993 state->sub.status = NT_STATUS_INTERNAL_ERROR;
1995 if (NT_STATUS_IS_OK(status)) {
1997 * Call finish_fn() with an empty
1998 * blob and NT_STATUS_OK.
2000 state->sub.status = NT_STATUS_OK;
2003 * MORE_PROCESSING_REQUIRED...
2005 state->sub.needed = true;
2009 if (state->sub.needed) {
2010 struct tevent_req *subreq = NULL;
2013 * We may need one more roundtrip...
2015 subreq = gensec_update_send(state, state->ev,
2016 spnego_state->sub_sec_security,
2018 if (tevent_req_nomem(subreq, req)) {
2021 tevent_req_set_callback(subreq,
2022 gensec_spnego_update_done,
2024 state->sub.needed = false;
2028 status = ops->finish_fn(state->gensec,
2035 &spnego_state->out_frag);
2036 TALLOC_FREE(state->n);
2037 if (GENSEC_UPDATE_IS_NTERROR(status)) {
2038 tevent_req_nterror(req, status);
2042 if (NT_STATUS_IS_OK(status)) {
2043 bool reset_full = true;
2045 reset_full = !spnego_state->done_mic_check;
2047 status = gensec_may_reset_crypto(spnego_state->sub_sec_security,
2049 if (tevent_req_nterror(req, status)) {
2055 spnego_state->out_status = status;
2057 status = gensec_spnego_update_out(state->gensec,
2058 state, &state->out);
2059 if (GENSEC_UPDATE_IS_NTERROR(status)) {
2060 tevent_req_nterror(req, status);
2064 state->status = status;
2065 tevent_req_done(req);
2069 static NTSTATUS gensec_spnego_update_out(struct gensec_security *gensec_security,
2070 TALLOC_CTX *out_mem_ctx,
2073 struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data;
2074 DATA_BLOB out = data_blob_null;
2077 *_out = data_blob_null;
2079 if (spnego_state->out_frag.length <= spnego_state->out_max_length) {
2081 * Fast path, we can deliver everything
2084 *_out = spnego_state->out_frag;
2085 if (spnego_state->out_frag.length > 0) {
2086 talloc_steal(out_mem_ctx, _out->data);
2087 spnego_state->out_frag = data_blob_null;
2090 if (!NT_STATUS_IS_OK(spnego_state->out_status)) {
2091 return spnego_state->out_status;
2095 * We're completely done, further updates are not allowed.
2097 spnego_state->state_position = SPNEGO_DONE;
2098 return gensec_child_ready(gensec_security,
2099 spnego_state->sub_sec_security);
2102 out = spnego_state->out_frag;
2105 * copy the remaining bytes
2107 spnego_state->out_frag = data_blob_talloc(spnego_state,
2108 out.data + spnego_state->out_max_length,
2109 out.length - spnego_state->out_max_length);
2110 if (spnego_state->out_frag.data == NULL) {
2111 return NT_STATUS_NO_MEMORY;
2115 * truncate the buffer
2117 ok = data_blob_realloc(spnego_state, &out,
2118 spnego_state->out_max_length);
2120 return NT_STATUS_NO_MEMORY;
2123 talloc_steal(out_mem_ctx, out.data);
2125 return NT_STATUS_MORE_PROCESSING_REQUIRED;
2128 static NTSTATUS gensec_spnego_update_recv(struct tevent_req *req,
2129 TALLOC_CTX *out_mem_ctx,
2132 struct gensec_spnego_update_state *state =
2133 tevent_req_data(req,
2134 struct gensec_spnego_update_state);
2137 *out = data_blob_null;
2139 if (tevent_req_is_nterror(req, &status)) {
2140 tevent_req_received(req);
2145 talloc_steal(out_mem_ctx, state->out.data);
2146 status = state->status;
2147 tevent_req_received(req);
2151 static const char *gensec_spnego_oids[] = {
2156 static const struct gensec_security_ops gensec_spnego_security_ops = {
2158 .sasl_name = "GSS-SPNEGO",
2159 .auth_type = DCERPC_AUTH_TYPE_SPNEGO,
2160 .oid = gensec_spnego_oids,
2161 .client_start = gensec_spnego_client_start,
2162 .server_start = gensec_spnego_server_start,
2163 .update_send = gensec_spnego_update_send,
2164 .update_recv = gensec_spnego_update_recv,
2165 .seal_packet = gensec_child_seal_packet,
2166 .sign_packet = gensec_child_sign_packet,
2167 .sig_size = gensec_child_sig_size,
2168 .max_wrapped_size = gensec_child_max_wrapped_size,
2169 .max_input_size = gensec_child_max_input_size,
2170 .check_packet = gensec_child_check_packet,
2171 .unseal_packet = gensec_child_unseal_packet,
2172 .wrap = gensec_child_wrap,
2173 .unwrap = gensec_child_unwrap,
2174 .session_key = gensec_child_session_key,
2175 .session_info = gensec_child_session_info,
2176 .want_feature = gensec_child_want_feature,
2177 .have_feature = gensec_child_have_feature,
2178 .expire_time = gensec_child_expire_time,
2179 .final_auth_type = gensec_child_final_auth_type,
2181 .priority = GENSEC_SPNEGO
2184 _PUBLIC_ NTSTATUS gensec_spnego_init(TALLOC_CTX *ctx)
2187 ret = gensec_register(ctx, &gensec_spnego_security_ops);
2188 if (!NT_STATUS_IS_OK(ret)) {
2189 DEBUG(0,("Failed to register '%s' gensec backend!\n",
2190 gensec_spnego_security_ops.name));