const char *neg_oid;
DATA_BLOB mech_types;
+ size_t num_targs;
+ bool mic_requested;
+ bool needs_mic_sign;
+ bool needs_mic_check;
+ bool done_mic_check;
/*
* The following is used to implement
spnego_state->neg_oid = all_sec[i].oid;
*unwrapped_out = data_blob_null;
nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+ /*
+ * Indicate the downgrade and request a
+ * mic.
+ */
+ spnego_state->mic_requested = true;
break;
}
/* 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.mechListMIC = mech_list_mic;
spnego_out.negTokenTarg.supportedMech = NULL;
if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
spnego_out.negTokenTarg.supportedMech = spnego_state->neg_oid;
- spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
+ if (spnego_state->mic_requested) {
+ spnego_out.negTokenTarg.negResult = SPNEGO_REQUEST_MIC;
+ spnego_state->mic_requested = false;
+ } else {
+ 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->neg_oid;
}
spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED;
- spnego_out.negTokenTarg.mechListMIC = mech_list_mic;
spnego_state->state_position = SPNEGO_DONE;
} else {
spnego_out.negTokenTarg.negResult = SPNEGO_REJECT;
+ spnego_out.negTokenTarg.mechListMIC = null_data_blob;
DEBUG(2, ("SPNEGO login failed: %s\n", nt_errstr(nt_status)));
spnego_state->state_position = SPNEGO_DONE;
}
}
spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG;
+ spnego_state->num_targs++;
return nt_status;
}
return NT_STATUS_INVALID_PARAMETER;
}
+ spnego_state->num_targs++;
+
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;
}
+ if (spnego_state->needs_mic_check) {
+ if (spnego.negTokenTarg.responseToken.length != 0) {
+ DEBUG(1, ("SPNEGO: Did not setup a mech in NEG_TOKEN_INIT\n"));
+ spnego_free_data(&spnego);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ nt_status = gensec_check_packet(spnego_state->sub_sec_security,
+ spnego_state->mech_types.data,
+ spnego_state->mech_types.length,
+ spnego_state->mech_types.data,
+ spnego_state->mech_types.length,
+ &spnego.negTokenTarg.mechListMIC);
+ if (NT_STATUS_IS_OK(nt_status)) {
+ spnego_state->needs_mic_check = false;
+ spnego_state->done_mic_check = true;
+ } else {
+ DEBUG(2,("GENSEC SPNEGO: failed to verify mechListMIC: %s\n",
+ nt_errstr(nt_status)));
+ }
+ goto server_response;
+ }
+
nt_status = gensec_update_ev(spnego_state->sub_sec_security,
- out_mem_ctx, ev,
- spnego.negTokenTarg.responseToken,
- &unwrapped_out);
- if (NT_STATUS_IS_OK(nt_status) && spnego.negTokenTarg.mechListMIC.length > 0) {
+ out_mem_ctx, ev,
+ spnego.negTokenTarg.responseToken,
+ &unwrapped_out);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ goto server_response;
+ }
+
+ new_spnego = gensec_have_feature(spnego_state->sub_sec_security,
+ GENSEC_FEATURE_NEW_SPNEGO);
+ if (spnego.negTokenTarg.mechListMIC.length > 0) {
new_spnego = true;
+ }
+
+ if (new_spnego) {
+ spnego_state->needs_mic_check = true;
+ spnego_state->needs_mic_sign = true;
+ }
+
+ if (spnego.negTokenTarg.mechListMIC.length > 0) {
nt_status = gensec_check_packet(spnego_state->sub_sec_security,
spnego_state->mech_types.data,
spnego_state->mech_types.length,
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(2,("GENSEC SPNEGO: failed to verify mechListMIC: %s\n",
nt_errstr(nt_status)));
+ goto server_response;
}
+
+ spnego_state->needs_mic_check = false;
+ spnego_state->done_mic_check = true;
}
- if (NT_STATUS_IS_OK(nt_status) && new_spnego) {
+
+ if (spnego_state->needs_mic_sign) {
nt_status = gensec_sign_packet(spnego_state->sub_sec_security,
out_mem_ctx,
spnego_state->mech_types.data,
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(2,("GENSEC SPNEGO: failed to sign mechListMIC: %s\n",
nt_errstr(nt_status)));
+ goto server_response;
}
+ spnego_state->needs_mic_sign = false;
}
+ if (spnego_state->needs_mic_check) {
+ nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ server_response:
nt_status = gensec_spnego_server_negTokenTarg(spnego_state,
out_mem_ctx,
nt_status,
}
case SPNEGO_CLIENT_TARG:
{
- NTSTATUS nt_status;
+ NTSTATUS nt_status = NT_STATUS_INTERNAL_ERROR;
+
if (!in.length) {
return NT_STATUS_INVALID_PARAMETER;
}
return NT_STATUS_INVALID_PARAMETER;
}
+ spnego_state->num_targs++;
+
if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) {
spnego_free_data(&spnego);
return NT_STATUS_LOGON_FAILURE;
}
+ if (spnego.negTokenTarg.negResult == SPNEGO_REQUEST_MIC) {
+ spnego_state->mic_requested = true;
+ }
+
/* Server didn't like our choice of mech, and chose something else */
if (((spnego.negTokenTarg.negResult == SPNEGO_ACCEPT_INCOMPLETE) ||
(spnego.negTokenTarg.negResult == SPNEGO_REQUEST_MIC)) &&
return nt_status;
}
- nt_status = gensec_update_ev(spnego_state->sub_sec_security,
- out_mem_ctx, ev,
- 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;
- } 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;
+ spnego_state->neg_oid = talloc_strdup(spnego_state,
+ spnego.negTokenTarg.supportedMech);
+ if (spnego_state->neg_oid == NULL) {
+ spnego_free_data(&spnego);
+ return NT_STATUS_NO_MEMORY;
+ };
+ }
+
+ if (spnego.negTokenTarg.mechListMIC.length > 0) {
+ if (spnego_state->no_response_expected) {
+ spnego_state->needs_mic_check = true;
}
- if (NT_STATUS_IS_OK(nt_status) && spnego.negTokenTarg.mechListMIC.length > 0) {
- nt_status = gensec_check_packet(spnego_state->sub_sec_security,
- spnego_state->mech_types.data,
- spnego_state->mech_types.length,
- spnego_state->mech_types.data,
- spnego_state->mech_types.length,
- &spnego.negTokenTarg.mechListMIC);
- if (!NT_STATUS_IS_OK(nt_status)) {
- DEBUG(2,("GENSEC SPNEGO: failed to verify mechListMIC: %s\n",
- nt_errstr(nt_status)));
- }
+ }
+
+ if (spnego_state->needs_mic_check) {
+ if (spnego.negTokenTarg.responseToken.length != 0) {
+ DEBUG(1, ("SPNEGO: Did not setup a mech in NEG_TOKEN_INIT\n"));
+ spnego_free_data(&spnego);
+ return NT_STATUS_INVALID_PARAMETER;
}
- } else {
- bool new_spnego = false;
+ nt_status = gensec_check_packet(spnego_state->sub_sec_security,
+ spnego_state->mech_types.data,
+ spnego_state->mech_types.length,
+ spnego_state->mech_types.data,
+ spnego_state->mech_types.length,
+ &spnego.negTokenTarg.mechListMIC);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(2,("GENSEC SPNEGO: failed to verify mechListMIC: %s\n",
+ nt_errstr(nt_status)));
+ spnego_free_data(&spnego);
+ return nt_status;
+ }
+ spnego_state->needs_mic_check = false;
+ spnego_state->done_mic_check = true;
+ goto client_response;
+ }
+
+ if (!spnego_state->no_response_expected) {
nt_status = gensec_update_ev(spnego_state->sub_sec_security,
out_mem_ctx, ev,
spnego.negTokenTarg.responseToken,
&unwrapped_out);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ goto client_response;
+ }
+
+ spnego_state->no_response_expected = true;
+ } else {
+ nt_status = NT_STATUS_OK;
+ }
+
+ if (spnego_state->no_response_expected &&
+ !spnego_state->done_mic_check)
+ {
+ bool new_spnego = false;
+
+ new_spnego = gensec_have_feature(spnego_state->sub_sec_security,
+ GENSEC_FEATURE_NEW_SPNEGO);
+
+ switch (spnego.negTokenTarg.negResult) {
+ case SPNEGO_ACCEPT_COMPLETED:
+ case SPNEGO_NONE_RESULT:
+ if (spnego_state->num_targs == 1) {
+ /*
+ * the first exchange doesn't require
+ * verification
+ */
+ new_spnego = false;
+ }
+ break;
- if (NT_STATUS_IS_OK(nt_status)
- && spnego.negTokenTarg.negResult != SPNEGO_ACCEPT_COMPLETED) {
- new_spnego = gensec_have_feature(spnego_state->sub_sec_security,
- GENSEC_FEATURE_NEW_SPNEGO);
+ case SPNEGO_ACCEPT_INCOMPLETE:
+ case SPNEGO_REQUEST_MIC:
+ if (spnego.negTokenTarg.mechListMIC.length > 0) {
+ new_spnego = true;
+ }
+ break;
+ default:
+ break;
}
- if (NT_STATUS_IS_OK(nt_status) && new_spnego) {
- nt_status = gensec_sign_packet(spnego_state->sub_sec_security,
- out_mem_ctx,
- spnego_state->mech_types.data,
- spnego_state->mech_types.length,
- spnego_state->mech_types.data,
- spnego_state->mech_types.length,
- &mech_list_mic);
- if (!NT_STATUS_IS_OK(nt_status)) {
- DEBUG(2,("GENSEC SPNEGO: failed to sign mechListMIC: %s\n",
- nt_errstr(nt_status)));
+
+ if (spnego_state->mic_requested) {
+ bool sign;
+
+ sign = gensec_have_feature(spnego_state->sub_sec_security,
+ GENSEC_FEATURE_SIGN);
+ if (sign) {
+ new_spnego = true;
}
}
- if (NT_STATUS_IS_OK(nt_status)) {
- spnego_state->no_response_expected = true;
+
+ if (new_spnego) {
+ spnego_state->needs_mic_check = true;
+ spnego_state->needs_mic_sign = true;
+ }
+ }
+
+ if (spnego.negTokenTarg.mechListMIC.length > 0) {
+ nt_status = gensec_check_packet(spnego_state->sub_sec_security,
+ spnego_state->mech_types.data,
+ spnego_state->mech_types.length,
+ spnego_state->mech_types.data,
+ spnego_state->mech_types.length,
+ &spnego.negTokenTarg.mechListMIC);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(2,("GENSEC SPNEGO: failed to verify mechListMIC: %s\n",
+ nt_errstr(nt_status)));
+ spnego_free_data(&spnego);
+ return nt_status;
+ }
+ spnego_state->needs_mic_check = false;
+ spnego_state->done_mic_check = true;
+ }
+
+ if (spnego_state->needs_mic_sign) {
+ nt_status = gensec_sign_packet(spnego_state->sub_sec_security,
+ out_mem_ctx,
+ spnego_state->mech_types.data,
+ spnego_state->mech_types.length,
+ spnego_state->mech_types.data,
+ spnego_state->mech_types.length,
+ &mech_list_mic);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(2,("GENSEC SPNEGO: failed to sign mechListMIC: %s\n",
+ nt_errstr(nt_status)));
+ spnego_free_data(&spnego);
+ return nt_status;
}
- }
+ spnego_state->needs_mic_sign = false;
+ }
+
+ if (spnego_state->needs_mic_check) {
+ nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+ }
+ client_response:
spnego_free_data(&spnego);
if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
return NT_STATUS_INVALID_PARAMETER;
}
+ spnego_state->num_targs++;
spnego_state->state_position = SPNEGO_CLIENT_TARG;
nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
} else {