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-2005
Copyright (C) Stefan Metzmacher <metze@samba.org> 2004-2008
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
*/
&& spnego_state->state_position != SPNEGO_FALLBACK) {
return NT_STATUS_INVALID_PARAMETER;
}
-
+
return gensec_unseal_packet(spnego_state->sub_sec_security,
data, length,
whole_pdu, pdu_length,
&& spnego_state->state_position != SPNEGO_FALLBACK) {
return NT_STATUS_INVALID_PARAMETER;
}
-
+
return gensec_check_packet(spnego_state->sub_sec_security,
data, length,
whole_pdu, pdu_length,
&& spnego_state->state_position != SPNEGO_FALLBACK) {
return NT_STATUS_INVALID_PARAMETER;
}
-
+
return gensec_seal_packet(spnego_state->sub_sec_security,
mem_ctx,
data, length,
&& spnego_state->state_position != SPNEGO_FALLBACK) {
return NT_STATUS_INVALID_PARAMETER;
}
-
+
return gensec_sign_packet(spnego_state->sub_sec_security,
mem_ctx,
data, length,
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);
}
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);
}
DEBUG(1, ("gensec_spnego_wrap: wrong state for wrap\n"));
return NT_STATUS_INVALID_PARAMETER;
}
-
+
return gensec_wrap_packets(spnego_state->sub_sec_security,
mem_ctx, in, out,
len_processed);
DEBUG(1, ("gensec_spnego_unwrap: wrong state for unwrap\n"));
return NT_STATUS_INVALID_PARAMETER;
}
-
+
return gensec_packet_full_request(spnego_state->sub_sec_security,
blob, size);
}
DEBUG(1, ("gensec_spnego_unwrap: wrong state for unwrap\n"));
return NT_STATUS_INVALID_PARAMETER;
}
-
+
return gensec_unwrap_packets(spnego_state->sub_sec_security,
mem_ctx, in, out,
len_processed);
&& spnego_state->state_position != SPNEGO_FALLBACK) {
return 0;
}
-
+
return gensec_sig_size(spnego_state->sub_sec_security, data_size);
}
&& spnego_state->state_position != SPNEGO_FALLBACK) {
return 0;
}
-
+
return gensec_max_input_size(spnego_state->sub_sec_security);
}
&& spnego_state->state_position != SPNEGO_FALLBACK) {
return 0;
}
-
+
return gensec_max_wrapped_size(spnego_state->sub_sec_security);
}
if (!spnego_state->sub_sec_security) {
return NT_STATUS_INVALID_PARAMETER;
}
-
+
return gensec_session_key(spnego_state->sub_sec_security,
mem_ctx,
session_key);
if (!spnego_state->sub_sec_security) {
return NT_STATUS_INVALID_PARAMETER;
}
-
+
return gensec_session_info(spnego_state->sub_sec_security,
mem_ctx,
session_info);
}
DEBUG(1, ("Failed to parse SPNEGO request\n"));
return NT_STATUS_INVALID_PARAMETER;
-
}
/*
if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER) ||
NT_STATUS_EQUAL(nt_status, NT_STATUS_CANT_ACCESS_DOMAIN_INFO)) {
/* Pretend we never started it (lets the first run find some incompatible demand) */
-
+
DEBUG(1, ("SPNEGO(%s) NEG_TOKEN_INIT failed to parse contents: %s\n",
spnego_state->sub_sec_security->ops->name, nt_errstr(nt_status)));
talloc_free(spnego_state->sub_sec_security);
return NT_STATUS_INVALID_PARAMETER;
}
}
-
+
/* Having tried any optimistic token from the client (if we
* were the server), if we didn't get anywhere, walk our list
* in our preference order */
-
+
if (!spnego_state->sub_sec_security) {
for (i=0; all_sec && all_sec[i].op; i++) {
nt_status = gensec_subcontext_start(spnego_state,
spnego_state->sub_sec_security = NULL;
continue;
}
-
+
spnego_state->neg_oid = all_sec[i].oid;
/* only get the helping start blob for the first OID */
NT_STATUS_EQUAL(nt_status, NT_STATUS_TIME_DIFFERENCE_AT_DC) ||
NT_STATUS_EQUAL(nt_status, NT_STATUS_CANT_ACCESS_DOMAIN_INFO)) {
/* Pretend we never started it (lets the first run find some incompatible demand) */
-
+
DEBUG(3, ("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);
* just push us along the merry-go-round
* again, and hope for better luck next
* time */
-
+
if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
*unwrapped_out = data_blob(NULL, 0);
nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
}
-
+
if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)
&& !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
&& !NT_STATUS_IS_OK(nt_status)) {
spnego_state->sub_sec_security->ops->name, nt_errstr(nt_status)));
talloc_free(spnego_state->sub_sec_security);
spnego_state->sub_sec_security = NULL;
-
+
/* We started the mech correctly, and the
* input from the other side was valid.
* Return the error (say bad password, invalid
* ticket) */
return nt_status;
}
-
-
+
return nt_status; /* OK, INVALID_PARAMETER ore MORE PROCESSING */
}
ev,
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) creating NEG_TOKEN_INIT failed: %s\n",
talloc_free(spnego_state->sub_sec_security);
spnego_state->sub_sec_security = NULL;
/* Pretend we never started it (lets the first run find some incompatible demand) */
-
+
continue;
}
}
spnego_out.negTokenInit.mechTypes = send_mech_types;
spnego_out.negTokenInit.reqFlags = null_data_blob;
spnego_out.negTokenInit.reqFlagsPadding = 0;
-
+
if (spnego_state->state_position == SPNEGO_SERVER_START) {
spnego_out.negTokenInit.mechListMIC
= data_blob_string_const(ADS_IGNORE_PRINCIPAL);
}
spnego_out.negTokenInit.mechToken = unwrapped_out;
-
+
if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
DEBUG(1, ("Failed to write NEG_TOKEN_INIT\n"));
return NT_STATUS_INVALID_PARAMETER;
}
-
+
/* set next state */
spnego_state->neg_oid = all_sec[i].oid;
-
+
if (NT_STATUS_IS_OK(nt_status)) {
spnego_state->no_response_expected = true;
}
spnego_free_data(&spnego);
return NT_STATUS_INVALID_PARAMETER;
}
-
+
nt_status = gensec_spnego_parse_negTokenInit(gensec_security,
spnego_state,
out_mem_ctx,
spnego.negTokenInit.mechTypes,
spnego.negTokenInit.mechToken,
&unwrapped_out);
-
+
nt_status = gensec_spnego_server_negTokenTarg(spnego_state,
out_mem_ctx,
nt_status,
unwrapped_out,
null_data_blob,
out);
-
+
spnego_free_data(&spnego);
-
+
return nt_status;
} else {
nt_status = gensec_spnego_create_negTokenInit(gensec_security, spnego_state,
return nt_status;
}
}
-
+
case SPNEGO_CLIENT_START:
{
/* The server offers a list of mechanisms */
-
+
const char *my_mechs[] = {NULL, NULL};
NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
return nt_status;
}
-
+
len = spnego_read_data(gensec_security, 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_out.negTokenInit.reqFlagsPadding = 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;
}
-
+
spnego_free_data(&spnego);
return NT_STATUS_MORE_PROCESSING_REQUIRED;
}
if (!in.length) {
return NT_STATUS_INVALID_PARAMETER;
}
-
+
len = spnego_read_data(gensec_security, 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,
unwrapped_out,
mech_list_mic,
out);
-
+
spnego_free_data(&spnego);
-
+
return nt_status;
}
case SPNEGO_CLIENT_TARG:
if (!in.length) {
return NT_STATUS_INVALID_PARAMETER;
}
-
+
len = spnego_read_data(gensec_security, 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_free_data(&spnego);
return NT_STATUS_INVALID_PARAMETER;
}
-
+
if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) {
spnego_free_data(&spnego);
return NT_STATUS_ACCESS_DENIED;
DEBUG(3,("GENSEC SPNEGO: client preferred mech (%s) not accepted, server wants: %s\n",
gensec_get_name_by_oid(gensec_security, spnego.negTokenTarg.supportedMech),
gensec_get_name_by_oid(gensec_security, spnego_state->neg_oid)));
-
+
talloc_free(spnego_state->sub_sec_security);
nt_status = gensec_subcontext_start(spnego_state,
gensec_security,
spnego_state->no_response_expected = true;
}
}
-
+
spnego_free_data(&spnego);
if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
spnego_out.negTokenTarg.supportedMech = NULL;
spnego_out.negTokenTarg.responseToken = unwrapped_out;
spnego_out.negTokenTarg.mechListMIC = mech_list_mic;
-
+
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 {
DEBUG(1,("gensec_update ok but not accepted\n"));
nt_status = NT_STATUS_INVALID_PARAMETER;
}
-
+
spnego_state->state_position = SPNEGO_DONE;
}
if (!spnego_state->sub_sec_security) {
return false;
}
-
+
return gensec_have_feature(spnego_state->sub_sec_security,
feature);
}