summaryrefslogtreecommitdiff
path: root/source4/auth/gensec/spnego.c
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2005-10-20 03:20:43 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:44:59 -0500
commitb0fe5e6ade0a5e8e3c298d994c7901c59f33cca3 (patch)
tree9c6fd224ef6e896ecc372e5794f44015c0f00290 /source4/auth/gensec/spnego.c
parent02c32587a88fa8a0a336981e7a5cf88042b75e6d (diff)
downloadsamba-b0fe5e6ade0a5e8e3c298d994c7901c59f33cca3.tar.gz
samba-b0fe5e6ade0a5e8e3c298d994c7901c59f33cca3.tar.bz2
samba-b0fe5e6ade0a5e8e3c298d994c7901c59f33cca3.zip
r11196: Clean up memory leaks (pointed out by vl), and handle the case where
the client doesn't guess correctly on the mech to use. It must back off and try the mech the server selected from the list. I'm not particularly attached to our SPNEGO parser, so while I can't easily use the SPNEGO application logic in Heimdal, I'm going to look closely at using the asn1 routines to avoid some pain here. Andrew Bartlett (This used to be commit 929217387449270b60c3f825dca3b3cae5a4f9d1)
Diffstat (limited to 'source4/auth/gensec/spnego.c')
-rw-r--r--source4/auth/gensec/spnego.c58
1 files changed, 47 insertions, 11 deletions
diff --git a/source4/auth/gensec/spnego.c b/source4/auth/gensec/spnego.c
index 570ca89f03..00d6e709eb 100644
--- a/source4/auth/gensec/spnego.c
+++ b/source4/auth/gensec/spnego.c
@@ -346,9 +346,11 @@ static NTSTATUS gensec_spnego_parse_negTokenInit(struct gensec_security *gensec_
null_data_blob,
unwrapped_out);
/* it is likely that a NULL input token will
- * not be liked by most mechs, so just push us
- * along the merry-go-round again, and hope
- * for better luck next time */
+ * not be liked by most server mechs, but this
+ * does the right thing in the CIFS client.
+ * 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);
@@ -473,6 +475,7 @@ static NTSTATUS gensec_spnego_create_negTokenInit(struct gensec_security *gensec
/* set next state */
spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
+ spnego_state->neg_oid = all_sec[i].oid;
if (NT_STATUS_IS_OK(nt_status)) {
spnego_state->no_response_expected = True;
@@ -488,7 +491,7 @@ static NTSTATUS gensec_spnego_create_negTokenInit(struct gensec_security *gensec
}
-/** create a client negTokenTarg
+/** create a server negTokenTarg
*
* This is the case, where the client is the first one who sends data
*/
@@ -565,7 +568,8 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
len = spnego_read_data(in, &spnego);
if (len == -1) {
- return gensec_spnego_server_try_fallback(gensec_security, spnego_state, out_mem_ctx, in, out);
+ return gensec_spnego_server_try_fallback(gensec_security, spnego_state,
+ out_mem_ctx, in, out);
}
/* client sent NegTargetInit, we send NegTokenTarg */
@@ -597,7 +601,7 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
return nt_status;
} else {
nt_status = gensec_spnego_create_negTokenInit(gensec_security, spnego_state,
- out_mem_ctx, in, out);
+ out_mem_ctx, in, out);
spnego_state->state_position = SPNEGO_SERVER_TARG;
return nt_status;
}
@@ -673,6 +677,7 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
spnego_state->no_response_expected = True;
}
+ spnego_free_data(&spnego);
return NT_STATUS_MORE_PROCESSING_REQUIRED;
}
case SPNEGO_SERVER_TARG:
@@ -701,6 +706,7 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
if (!spnego_state->sub_sec_security) {
DEBUG(1, ("SPNEGO: Did not setup a mech in NEG_TOKEN_INIT\n"));
+ spnego_free_data(&spnego);
return NT_STATUS_INVALID_PARAMETER;
}
@@ -715,7 +721,7 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
nt_status,
unwrapped_out,
out);
-
+
spnego_free_data(&spnego);
return nt_status;
@@ -745,10 +751,39 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
}
if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) {
+ spnego_free_data(&spnego);
return NT_STATUS_ACCESS_DENIED;
}
- if (spnego_state->no_response_expected) {
+ /* Server didn't like our choice of mech, and chose something else */
+ if ((spnego.negTokenTarg.negResult == SPNEGO_ACCEPT_INCOMPLETE) &&
+ strcmp(spnego.negTokenTarg.supportedMech, spnego_state->neg_oid) != 0) {
+ DEBUG(3,("GENSEC SPNEGO: client preferred mech (%s) not accepted, server wants: %s\n",
+ gensec_get_name_by_oid(spnego.negTokenTarg.supportedMech),
+ gensec_get_name_by_oid(spnego_state->neg_oid)));
+
+ talloc_free(spnego_state->sub_sec_security);
+ nt_status = gensec_subcontext_start(spnego_state,
+ gensec_security,
+ &spnego_state->sub_sec_security);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ spnego_free_data(&spnego);
+ return nt_status;
+ }
+ /* select the sub context */
+ nt_status = gensec_start_mech_by_oid(spnego_state->sub_sec_security,
+ spnego.negTokenTarg.supportedMech);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ spnego_free_data(&spnego);
+ return nt_status;
+ }
+
+ nt_status = gensec_update(spnego_state->sub_sec_security,
+ out_mem_ctx,
+ spnego.negTokenTarg.responseToken,
+ &unwrapped_out);
+ spnego_state->neg_oid = talloc_strdup(spnego_state, spnego.negTokenTarg.supportedMech);
+ } else 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;
@@ -804,14 +839,15 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
DEBUG(1,("gensec_update ok but not accepted\n"));
nt_status = NT_STATUS_INVALID_PARAMETER;
}
- }
- spnego_state->state_position = SPNEGO_DONE;
+ spnego_state->state_position = SPNEGO_DONE;
+ }
return nt_status;
}
case SPNEGO_DONE:
- return NT_STATUS_OK;
+ /* We should not be called after we are 'done' */
+ return NT_STATUS_INVALID_PARAMETER;
}
return NT_STATUS_INVALID_PARAMETER;
}