diff options
Diffstat (limited to 'source4/libcli/auth/spnego.c')
-rw-r--r-- | source4/libcli/auth/spnego.c | 884 |
1 files changed, 0 insertions, 884 deletions
diff --git a/source4/libcli/auth/spnego.c b/source4/libcli/auth/spnego.c deleted file mode 100644 index f5a091cd78..0000000000 --- a/source4/libcli/auth/spnego.c +++ /dev/null @@ -1,884 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - RFC2478 Compliant SPNEGO implementation - - Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003 - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "auth/auth.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_AUTH - -enum spnego_state_position { - SPNEGO_SERVER_START, - SPNEGO_CLIENT_START, - SPNEGO_SERVER_TARG, - SPNEGO_CLIENT_TARG, - SPNEGO_FALLBACK, - SPNEGO_DONE -}; - -struct spnego_state { - uint_t ref_count; - enum spnego_message_type expected_packet; - enum spnego_state_position state_position; - struct gensec_security *sub_sec_security; - BOOL no_response_expected; -}; - - -static NTSTATUS gensec_spnego_client_start(struct gensec_security *gensec_security) -{ - struct spnego_state *spnego_state; - - spnego_state = talloc(gensec_security, struct spnego_state); - if (!spnego_state) { - return NT_STATUS_NO_MEMORY; - } - - spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT; - spnego_state->state_position = SPNEGO_CLIENT_START; - spnego_state->sub_sec_security = NULL; - spnego_state->no_response_expected = False; - - gensec_security->private_data = spnego_state; - return NT_STATUS_OK; -} - -static NTSTATUS gensec_spnego_server_start(struct gensec_security *gensec_security) -{ - struct spnego_state *spnego_state; - - spnego_state = talloc(gensec_security, struct spnego_state); - if (!spnego_state) { - return NT_STATUS_NO_MEMORY; - } - - spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT; - spnego_state->state_position = SPNEGO_SERVER_START; - spnego_state->sub_sec_security = NULL; - spnego_state->no_response_expected = False; - - gensec_security->private_data = spnego_state; - return NT_STATUS_OK; -} - -/* - wrappers for the spnego_*() functions -*/ -static NTSTATUS gensec_spnego_unseal_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - struct spnego_state *spnego_state = gensec_security->private_data; - - if (spnego_state->state_position != SPNEGO_DONE - && spnego_state->state_position != SPNEGO_FALLBACK) { - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_unseal_packet(spnego_state->sub_sec_security, - mem_ctx, - data, length, - whole_pdu, pdu_length, - sig); -} - -static NTSTATUS gensec_spnego_check_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - const DATA_BLOB *sig) -{ - struct spnego_state *spnego_state = gensec_security->private_data; - - if (spnego_state->state_position != SPNEGO_DONE - && spnego_state->state_position != SPNEGO_FALLBACK) { - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_check_packet(spnego_state->sub_sec_security, - mem_ctx, - data, length, - whole_pdu, pdu_length, - sig); -} - -static NTSTATUS gensec_spnego_seal_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - struct spnego_state *spnego_state = gensec_security->private_data; - - if (spnego_state->state_position != SPNEGO_DONE - && spnego_state->state_position != SPNEGO_FALLBACK) { - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_seal_packet(spnego_state->sub_sec_security, - mem_ctx, - data, length, - whole_pdu, pdu_length, - sig); -} - -static NTSTATUS gensec_spnego_sign_packet(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const uint8_t *data, size_t length, - const uint8_t *whole_pdu, size_t pdu_length, - DATA_BLOB *sig) -{ - struct spnego_state *spnego_state = gensec_security->private_data; - - if (spnego_state->state_position != SPNEGO_DONE - && spnego_state->state_position != SPNEGO_FALLBACK) { - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_sign_packet(spnego_state->sub_sec_security, - mem_ctx, - data, length, - whole_pdu, pdu_length, - sig); -} - -static NTSTATUS gensec_spnego_wrap(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out) -{ - struct spnego_state *spnego_state = gensec_security->private_data; - - if (spnego_state->state_position != SPNEGO_DONE - && spnego_state->state_position != SPNEGO_FALLBACK) { - DEBUG(1, ("gensec_spnego_wrap: wrong state for wrap\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_wrap(spnego_state->sub_sec_security, - mem_ctx, in, out); -} - -static NTSTATUS gensec_spnego_unwrap(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out) -{ - struct spnego_state *spnego_state = gensec_security->private_data; - - if (spnego_state->state_position != SPNEGO_DONE - && spnego_state->state_position != SPNEGO_FALLBACK) { - DEBUG(1, ("gensec_spnego_unwrap: wrong state for unwrap\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_unwrap(spnego_state->sub_sec_security, - mem_ctx, in, out); -} - -static size_t gensec_spnego_sig_size(struct gensec_security *gensec_security) -{ - struct spnego_state *spnego_state = gensec_security->private_data; - - if (spnego_state->state_position != SPNEGO_DONE - && spnego_state->state_position != SPNEGO_FALLBACK) { - return 0; - } - - return gensec_sig_size(spnego_state->sub_sec_security); -} - -static NTSTATUS gensec_spnego_session_key(struct gensec_security *gensec_security, - DATA_BLOB *session_key) -{ - struct spnego_state *spnego_state = gensec_security->private_data; - if (!spnego_state->sub_sec_security) { - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_session_key(spnego_state->sub_sec_security, - session_key); -} - -static NTSTATUS gensec_spnego_session_info(struct gensec_security *gensec_security, - struct auth_session_info **session_info) -{ - struct spnego_state *spnego_state = gensec_security->private_data; - if (!spnego_state->sub_sec_security) { - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_session_info(spnego_state->sub_sec_security, - session_info); -} - -/** Fallback to another GENSEC mechanism, based on magic strings - * - * This is the 'fallback' case, where we don't get SPNEGO, and have to - * try all the other options (and hope they all have a magic string - * they check) -*/ - -static NTSTATUS gensec_spnego_server_try_fallback(struct gensec_security *gensec_security, - struct spnego_state *spnego_state, - TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out) -{ - int i; - int num_ops; - const struct gensec_security_ops **all_ops = gensec_security_all(&num_ops); - for (i=0; i < num_ops; i++) { - NTSTATUS nt_status; - if (!all_ops[i]->oid) { - continue; - } - if (strcasecmp(GENSEC_OID_SPNEGO,all_ops[i]->oid) == 0) { - continue; - } - - nt_status = gensec_subcontext_start(spnego_state, - gensec_security, - &spnego_state->sub_sec_security); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - /* select the sub context */ - nt_status = gensec_start_mech_by_oid(spnego_state->sub_sec_security, - all_ops[i]->oid); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(spnego_state->sub_sec_security); - spnego_state->sub_sec_security = NULL; - continue; - } - nt_status = gensec_update(spnego_state->sub_sec_security, - out_mem_ctx, in, out); - if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - spnego_state->state_position = SPNEGO_FALLBACK; - return nt_status; - } - talloc_free(spnego_state->sub_sec_security); - spnego_state->sub_sec_security = NULL; - } - DEBUG(1, ("Failed to parse SPNEGO request\n")); - return NT_STATUS_INVALID_PARAMETER; - -} - -/* - Parse the netTokenInit from the client, to the server. - - -*/ - -static NTSTATUS gensec_spnego_server_parse_negTokenInit(struct gensec_security *gensec_security, - struct spnego_state *spnego_state, - TALLOC_CTX *out_mem_ctx, - const char **mechType, - const DATA_BLOB unwrapped_in, DATA_BLOB *unwrapped_out) -{ - NTSTATUS nt_status; - - if (!mechType || !mechType[0]) { - DEBUG(1, ("SPNEGO: Could not find a suitable mechtype in NEG_TOKEN_INIT\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - nt_status = gensec_subcontext_start(spnego_state, - gensec_security, - &spnego_state->sub_sec_security); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - /* select the sub context */ - nt_status = gensec_start_mech_by_oid(spnego_state->sub_sec_security, - mechType[0]); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(spnego_state->sub_sec_security); - spnego_state->sub_sec_security = NULL; - return nt_status; - } - - if (!unwrapped_in.length) { - return NT_STATUS_INVALID_PARAMETER; - } - - nt_status = gensec_update(spnego_state->sub_sec_security, - out_mem_ctx, - unwrapped_in, - unwrapped_out); - - if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(nt_status)) { - DEBUG(1, ("SPNEGO(%s) NEG_TOKEN_INIT failed: %s\n", - spnego_state->sub_sec_security->ops->name, nt_errstr(nt_status))); - talloc_free(spnego_state->sub_sec_security); - spnego_state->sub_sec_security = NULL; - } - return nt_status; -} - -static NTSTATUS gensec_spnego_client_parse_negTokenInit(struct gensec_security *gensec_security, - struct spnego_state *spnego_state, - TALLOC_CTX *out_mem_ctx, - const char **mechType, - const DATA_BLOB unwrapped_in, DATA_BLOB *unwrapped_out) -{ - int i; - NTSTATUS nt_status; - DATA_BLOB null_data_blob = data_blob(NULL,0); - - for (i=0; mechType && mechType[i]; i++) { - nt_status = gensec_subcontext_start(spnego_state, - gensec_security, - &spnego_state->sub_sec_security); - if (!NT_STATUS_IS_OK(nt_status)) { - break; - } - /* select the sub context */ - nt_status = gensec_start_mech_by_oid(spnego_state->sub_sec_security, - mechType[i]); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(spnego_state->sub_sec_security); - spnego_state->sub_sec_security = NULL; - continue; - } - - if (i == 0) { - nt_status = gensec_update(spnego_state->sub_sec_security, - out_mem_ctx, - unwrapped_in, - unwrapped_out); - } else { - /* only get the helping start blob for the first OID */ - nt_status = gensec_update(spnego_state->sub_sec_security, - out_mem_ctx, - null_data_blob, - unwrapped_out); - } - if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(nt_status)) { - DEBUG(1, ("SPNEGO(%s) NEG_TOKEN_INIT failed: %s\n", - spnego_state->sub_sec_security->ops->name, nt_errstr(nt_status))); - talloc_free(spnego_state->sub_sec_security); - spnego_state->sub_sec_security = NULL; - } - return nt_status; - } - if (!mechType || !mechType[i]) { - DEBUG(1, ("SPNEGO: Could not find a suitable mechtype in NEG_TOKEN_INIT\n")); - } - return NT_STATUS_INVALID_PARAMETER; -} - -/** create a client negTokenInit - * - * This is the case, where the client is the first one who sends data -*/ - -static NTSTATUS gensec_spnego_client_negTokenInit(struct gensec_security *gensec_security, - struct spnego_state *spnego_state, - TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out) -{ - DATA_BLOB null_data_blob = data_blob(NULL,0); - NTSTATUS nt_status; - const char **mechTypes = NULL; - DATA_BLOB unwrapped_out = data_blob(NULL,0); - - mechTypes = gensec_security_oids(out_mem_ctx, GENSEC_OID_SPNEGO); - - if (!mechTypes) { - DEBUG(1, ("no GENSEC OID backends available\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - nt_status = gensec_subcontext_start(spnego_state, - gensec_security, - &spnego_state->sub_sec_security); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - /* select our preferred mech */ - nt_status = gensec_start_mech_by_oid(spnego_state->sub_sec_security, - mechTypes[0]); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(spnego_state->sub_sec_security); - spnego_state->sub_sec_security = NULL; - return nt_status; - } - nt_status = gensec_update(spnego_state->sub_sec_security, - out_mem_ctx, in, &unwrapped_out); - if (NT_STATUS_IS_OK(nt_status) || NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - struct spnego_data spnego_out; - spnego_out.type = SPNEGO_NEG_TOKEN_INIT; - spnego_out.negTokenInit.mechTypes = mechTypes; - spnego_out.negTokenInit.reqFlags = 0; - spnego_out.negTokenInit.mechListMIC = null_data_blob; - spnego_out.negTokenInit.mechToken = unwrapped_out; - - if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) { - DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_INIT\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - /* set next state */ - spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG; - spnego_state->state_position = SPNEGO_CLIENT_TARG; - - if (NT_STATUS_IS_OK(nt_status)) { - spnego_state->no_response_expected = True; - } - - return NT_STATUS_MORE_PROCESSING_REQUIRED; - } - talloc_free(spnego_state->sub_sec_security); - spnego_state->sub_sec_security = NULL; - - DEBUG(1, ("Failed to setup SPNEGO negTokenInit request: %s\n", nt_errstr(nt_status))); - return NT_STATUS_INVALID_PARAMETER; -} - - -/** create a client negTokenTarg - * - * This is the case, where the client is the first one who sends data -*/ - -static NTSTATUS gensec_spnego_server_negTokenTarg(struct gensec_security *gensec_security, - struct spnego_state *spnego_state, - TALLOC_CTX *out_mem_ctx, - NTSTATUS nt_status, - const DATA_BLOB unwrapped_out, DATA_BLOB *out) -{ - struct spnego_data spnego_out; - DATA_BLOB null_data_blob = data_blob(NULL, 0); - - /* compose reply */ - spnego_out.type = SPNEGO_NEG_TOKEN_TARG; - spnego_out.negTokenTarg.responseToken = unwrapped_out; - spnego_out.negTokenTarg.mechListMIC = null_data_blob; - spnego_out.negTokenTarg.supportedMech = NULL; - - if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - spnego_out.negTokenTarg.supportedMech - = spnego_state->sub_sec_security->ops->oid; - spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE; - spnego_state->state_position = SPNEGO_SERVER_TARG; - } else if (NT_STATUS_IS_OK(nt_status)) { - if (unwrapped_out.data) { - spnego_out.negTokenTarg.supportedMech - = spnego_state->sub_sec_security->ops->oid; - } - spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED; - spnego_state->state_position = SPNEGO_DONE; - } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) { - if (spnego_state->sub_sec_security) { - /* we have a mech, but we just didn't get the input parameter */ - spnego_out.negTokenTarg.supportedMech - = spnego_state->sub_sec_security->ops->oid; - } else { - const char **mechTypes = gensec_security_oids(out_mem_ctx, GENSEC_OID_SPNEGO); - if (!mechTypes) { - DEBUG(1, ("no GENSEC OID backends available\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - nt_status = gensec_subcontext_start(spnego_state, - gensec_security, - &spnego_state->sub_sec_security); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - /* select our preferred mech */ - nt_status = gensec_start_mech_by_oid(spnego_state->sub_sec_security, - mechTypes[0]); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(spnego_state->sub_sec_security); - spnego_state->sub_sec_security = NULL; - return nt_status; - } - - /* we should be sending the whole list here */ - spnego_out.negTokenTarg.supportedMech = mechTypes[0]; - } - - spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE; - spnego_state->state_position = SPNEGO_SERVER_TARG; - nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED; - } else { - spnego_out.negTokenTarg.negResult = SPNEGO_REJECT; - DEBUG(2, ("SPNEGO login failed: %s\n", nt_errstr(nt_status))); - spnego_state->state_position = SPNEGO_DONE; - } - - if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) { - DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG; - - return nt_status; -} - - -static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, - const DATA_BLOB in, DATA_BLOB *out) -{ - struct spnego_state *spnego_state = gensec_security->private_data; - DATA_BLOB null_data_blob = data_blob(NULL, 0); - DATA_BLOB unwrapped_out = data_blob(NULL, 0); - struct spnego_data spnego_out; - struct spnego_data spnego; - - ssize_t len; - - *out = data_blob(NULL, 0); - - if (!out_mem_ctx) { - out_mem_ctx = spnego_state; - } - - /* and switch into the state machine */ - - switch (spnego_state->state_position) { - case SPNEGO_FALLBACK: - return gensec_update(spnego_state->sub_sec_security, - out_mem_ctx, in, out); - case SPNEGO_SERVER_START: - { - if (in.length) { - NTSTATUS nt_status; - - len = spnego_read_data(in, &spnego); - if (len == -1) { - return gensec_spnego_server_try_fallback(gensec_security, spnego_state, out_mem_ctx, in, out); - } - /* client sent NegTargetInit, we send NegTokenTarg */ - - /* OK, so it's real SPNEGO, check the packet's the one we expect */ - if (spnego.type != spnego_state->expected_packet) { - DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego.type, - spnego_state->expected_packet)); - dump_data(1, in.data, in.length); - spnego_free_data(&spnego); - return NT_STATUS_INVALID_PARAMETER; - } - - nt_status = gensec_spnego_server_parse_negTokenInit(gensec_security, - spnego_state, - out_mem_ctx, - spnego.negTokenInit.mechTypes, - spnego.negTokenInit.mechToken, - &unwrapped_out); - - nt_status = gensec_spnego_server_negTokenTarg(gensec_security, - spnego_state, - out_mem_ctx, - nt_status, - unwrapped_out, - out); - - spnego_free_data(&spnego); - - return nt_status; - } else { - const char **mechlist = gensec_security_oids(out_mem_ctx, GENSEC_OID_SPNEGO); - - spnego_out.type = SPNEGO_NEG_TOKEN_INIT; - spnego_out.negTokenInit.mechTypes = mechlist; - spnego_out.negTokenInit.reqFlags = 0; - spnego_out.negTokenInit.mechListMIC - = data_blob_string_const(talloc_asprintf(out_mem_ctx, "%s$@%s", lp_netbios_name(), lp_realm())); - spnego_out.negTokenInit.mechToken = unwrapped_out; - - if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) { - DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_INIT\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - /* set next state */ - spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG; - spnego_state->state_position = SPNEGO_SERVER_TARG; - - return NT_STATUS_MORE_PROCESSING_REQUIRED; - } - } - - case SPNEGO_CLIENT_START: - { - /* The server offers a list of mechanisms */ - - const char *my_mechs[] = {NULL, NULL}; - NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER; - - if (!in.length) { - /* client to produce negTokenInit */ - return gensec_spnego_client_negTokenInit(gensec_security, spnego_state, - out_mem_ctx, in, out); - } - - len = spnego_read_data(in, &spnego); - - if (len == -1) { - DEBUG(1, ("Invalid SPNEGO request:\n")); - dump_data(1, in.data, in.length); - return NT_STATUS_INVALID_PARAMETER; - } - - /* OK, so it's real SPNEGO, check the packet's the one we expect */ - if (spnego.type != spnego_state->expected_packet) { - DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego.type, - spnego_state->expected_packet)); - dump_data(1, in.data, in.length); - spnego_free_data(&spnego); - return NT_STATUS_INVALID_PARAMETER; - } - - if (spnego.negTokenInit.targetPrincipal) { - DEBUG(5, ("Server claims it's principal name is %s (ignored)\n", spnego.negTokenInit.targetPrincipal)); - } - - nt_status = gensec_spnego_client_parse_negTokenInit(gensec_security, - spnego_state, - out_mem_ctx, - spnego.negTokenInit.mechTypes, - spnego.negTokenInit.mechToken, - &unwrapped_out); - - if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(nt_status)) { - spnego_free_data(&spnego); - return nt_status; - } - - /* compose reply */ - my_mechs[0] = spnego_state->sub_sec_security->ops->oid; - - spnego_out.type = SPNEGO_NEG_TOKEN_INIT; - spnego_out.negTokenInit.mechTypes = my_mechs; - spnego_out.negTokenInit.reqFlags = 0; - spnego_out.negTokenInit.mechListMIC = null_data_blob; - spnego_out.negTokenInit.mechToken = unwrapped_out; - - if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) { - DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_INIT\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - /* set next state */ - spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG; - spnego_state->state_position = SPNEGO_CLIENT_TARG; - - if (NT_STATUS_IS_OK(nt_status)) { - spnego_state->no_response_expected = True; - } - - return NT_STATUS_MORE_PROCESSING_REQUIRED; - } - case SPNEGO_SERVER_TARG: - { - NTSTATUS nt_status; - if (!in.length) { - return NT_STATUS_INVALID_PARAMETER; - } - - len = spnego_read_data(in, &spnego); - - if (len == -1) { - DEBUG(1, ("Invalid SPNEGO request:\n")); - dump_data(1, in.data, in.length); - return NT_STATUS_INVALID_PARAMETER; - } - - /* OK, so it's real SPNEGO, check the packet's the one we expect */ - if (spnego.type != spnego_state->expected_packet) { - DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego.type, - spnego_state->expected_packet)); - dump_data(1, in.data, in.length); - spnego_free_data(&spnego); - return NT_STATUS_INVALID_PARAMETER; - } - - if (!spnego_state->sub_sec_security) { - DEBUG(1, ("SPNEGO: Did not setup a mech in NEG_TOKEN_INIT\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - nt_status = gensec_update(spnego_state->sub_sec_security, - out_mem_ctx, - spnego.negTokenTarg.responseToken, - &unwrapped_out); - - nt_status = gensec_spnego_server_negTokenTarg(gensec_security, - spnego_state, - out_mem_ctx, - nt_status, - unwrapped_out, - out); - - spnego_free_data(&spnego); - - return nt_status; - } - case SPNEGO_CLIENT_TARG: - { - NTSTATUS nt_status; - if (!in.length) { - return NT_STATUS_INVALID_PARAMETER; - } - - len = spnego_read_data(in, &spnego); - - if (len == -1) { - DEBUG(1, ("Invalid SPNEGO request:\n")); - dump_data(1, in.data, in.length); - return NT_STATUS_INVALID_PARAMETER; - } - - /* OK, so it's real SPNEGO, check the packet's the one we expect */ - if (spnego.type != spnego_state->expected_packet) { - DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego.type, - spnego_state->expected_packet)); - dump_data(1, in.data, in.length); - spnego_free_data(&spnego); - return NT_STATUS_INVALID_PARAMETER; - } - - if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) { - return NT_STATUS_ACCESS_DENIED; - } - - if (spnego_state->no_response_expected) { - if (spnego.negTokenTarg.negResult != SPNEGO_ACCEPT_COMPLETED) { - DEBUG(3,("GENSEC SPNEGO: client GENSEC accepted, but server rejected (bad password?)\n")); - nt_status = NT_STATUS_INVALID_PARAMETER; - } else if (spnego.negTokenTarg.responseToken.length) { - DEBUG(2,("GENSEC SPNEGO: client GENSEC accepted, but server continued negotiation!\n")); - nt_status = NT_STATUS_INVALID_PARAMETER; - } else { - nt_status = NT_STATUS_OK; - } - } else { - nt_status = gensec_update(spnego_state->sub_sec_security, - out_mem_ctx, - spnego.negTokenTarg.responseToken, - &unwrapped_out); - - if (NT_STATUS_IS_OK(nt_status)) { - spnego_state->no_response_expected = True; - } - } - - spnego_free_data(&spnego); - - if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) - && !NT_STATUS_IS_OK(nt_status)) { - DEBUG(1, ("SPNEGO(%s) login failed: %s\n", - spnego_state->sub_sec_security->ops->name, - nt_errstr(nt_status))); - return nt_status; - } - - if (unwrapped_out.length) { - /* compose reply */ - spnego_out.type = SPNEGO_NEG_TOKEN_TARG; - spnego_out.negTokenTarg.negResult = SPNEGO_NONE_RESULT; - spnego_out.negTokenTarg.supportedMech = NULL; - spnego_out.negTokenTarg.responseToken = unwrapped_out; - spnego_out.negTokenTarg.mechListMIC = null_data_blob; - - if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) { - DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - spnego_state->state_position = SPNEGO_CLIENT_TARG; - nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED; - } else { - - /* all done - server has accepted, and we agree */ - *out = null_data_blob; - - if (spnego.negTokenTarg.negResult != SPNEGO_ACCEPT_COMPLETED) { - /* unless of course it did not accept */ - DEBUG(1,("gensec_update ok but not accepted\n")); - nt_status = NT_STATUS_INVALID_PARAMETER; - } - } - - spnego_state->state_position = SPNEGO_DONE; - - return nt_status; - } - case SPNEGO_DONE: - return NT_STATUS_OK; - } - return NT_STATUS_INVALID_PARAMETER; -} - -static BOOL gensec_spnego_have_feature(struct gensec_security *gensec_security, - uint32_t feature) -{ - struct spnego_state *spnego_state = gensec_security->private_data; - if (!spnego_state->sub_sec_security) { - return False; - } - - return gensec_have_feature(spnego_state->sub_sec_security, - feature); -} - -static const struct gensec_security_ops gensec_spnego_security_ops = { - .name = "spnego", - .sasl_name = "GSS-SPNEGO", - .auth_type = DCERPC_AUTH_TYPE_SPNEGO, - .oid = GENSEC_OID_SPNEGO, - .client_start = gensec_spnego_client_start, - .server_start = gensec_spnego_server_start, - .update = gensec_spnego_update, - .seal_packet = gensec_spnego_seal_packet, - .sign_packet = gensec_spnego_sign_packet, - .sig_size = gensec_spnego_sig_size, - .check_packet = gensec_spnego_check_packet, - .unseal_packet = gensec_spnego_unseal_packet, - .wrap = gensec_spnego_wrap, - .unwrap = gensec_spnego_unwrap, - .session_key = gensec_spnego_session_key, - .session_info = gensec_spnego_session_info, - .have_feature = gensec_spnego_have_feature, - .enabled = True -}; - -NTSTATUS gensec_spnego_init(void) -{ - NTSTATUS ret; - ret = gensec_register(&gensec_spnego_security_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register '%s' gensec backend!\n", - gensec_spnego_security_ops.name)); - return ret; - } - - return ret; -} |