diff options
Diffstat (limited to 'source4')
-rw-r--r-- | source4/libcli/auth/spnego.c | 76 |
1 files changed, 72 insertions, 4 deletions
diff --git a/source4/libcli/auth/spnego.c b/source4/libcli/auth/spnego.c index 5ba0e239c5..02bc9043f5 100644 --- a/source4/libcli/auth/spnego.c +++ b/source4/libcli/auth/spnego.c @@ -30,7 +30,8 @@ enum spnego_state_position { SPNEGO_SERVER_START, SPNEGO_CLIENT_START, - SPNEGO_TARG, + SPNEGO_SERVER_TARG, + SPNEGO_CLIENT_TARG, SPNEGO_FALLBACK, SPNEGO_DONE }; @@ -315,11 +316,11 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA /* set next state */ spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG; - spnego_state->state_position = SPNEGO_TARG; + spnego_state->state_position = SPNEGO_CLIENT_TARG; return nt_status; } - case SPNEGO_TARG: + case SPNEGO_SERVER_TARG: { NTSTATUS nt_status; if (!in.length) { @@ -375,7 +376,74 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA DEBUG(1, ("Failed to write SPENGO reply to NEG_TOKEN_TARG\n")); return NT_STATUS_INVALID_PARAMETER; } - spnego_state->state_position = SPNEGO_TARG; + spnego_state->state_position = SPNEGO_SERVER_TARG; + } else if (NT_STATUS_IS_OK(nt_status)) { + spnego_state->state_position = SPNEGO_DONE; + } else { + DEBUG(1, ("SPENGO(%s) login failed: %s\n", + spnego_state->sub_sec_security->ops->name, + nt_errstr(nt_status))); + return nt_status; + } + + 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) { + 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) { + spnego_free_data(&spnego); + DEBUG(1, ("Invalid SPENGO request: %d, expected %d\n", spnego.type, + spnego_state->expected_packet)); + return NT_STATUS_INVALID_PARAMETER; + } + + if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) { + return NT_STATUS_ACCESS_DENIED; + } + + if (spnego.negTokenTarg.responseToken.length) { + nt_status = gensec_update(spnego_state->sub_sec_security, + out_mem_ctx, + spnego.negTokenTarg.responseToken, + &unwrapped_out); + } else { + unwrapped_out = data_blob(NULL, 0); + nt_status = NT_STATUS_OK; + } + + if (NT_STATUS_IS_OK(nt_status) + && (spnego.negTokenTarg.negResult != SPNEGO_ACCEPT_COMPLETED)) { + nt_status = NT_STATUS_INVALID_PARAMETER; + } + + spnego_state->result = spnego.negTokenTarg.negResult; + spnego_free_data(&spnego); + + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + /* 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 SPENGO reply to NEG_TOKEN_TARG\n")); + return NT_STATUS_INVALID_PARAMETER; + } + spnego_state->state_position = SPNEGO_CLIENT_TARG; } else if (NT_STATUS_IS_OK(nt_status)) { spnego_state->state_position = SPNEGO_DONE; } else { |