diff options
author | Stefan Metzmacher <metze@samba.org> | 2017-05-15 23:37:22 +0200 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2017-05-21 21:05:13 +0200 |
commit | 3c2e02968e687a96cae30ba13d69205644f12dac (patch) | |
tree | c68d6788693ee7c303b8be6d2eaae4f627534658 /source4/libcli/smb2 | |
parent | 2c3e99d1697b83f7dd498596a274fe2e8e96116d (diff) | |
download | samba-3c2e02968e687a96cae30ba13d69205644f12dac.tar.gz |
s4:libcli/smb2: make smb2_session_setup_spnego_* completely async
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Diffstat (limited to 'source4/libcli/smb2')
-rw-r--r-- | source4/libcli/smb2/session.c | 253 |
1 files changed, 160 insertions, 93 deletions
diff --git a/source4/libcli/smb2/session.c b/source4/libcli/smb2/session.c index c96693b4c9e..e3e54cbe31a 100644 --- a/source4/libcli/smb2/session.c +++ b/source4/libcli/smb2/session.c @@ -115,11 +115,17 @@ struct smb2_session_setup_spnego_state { bool session_bind; bool reauth; NTSTATUS gensec_status; + NTSTATUS remote_status; DATA_BLOB in_secblob; DATA_BLOB out_secblob; + struct iovec *recv_iov; }; -static void smb2_session_setup_spnego_done(struct tevent_req *subreq); +static void smb2_session_setup_spnego_gensec_next(struct tevent_req *req); +static void smb2_session_setup_spnego_gensec_done(struct tevent_req *subreq); +static void smb2_session_setup_spnego_smb2_next(struct tevent_req *req); +static void smb2_session_setup_spnego_smb2_done(struct tevent_req *subreq); +static void smb2_session_setup_spnego_both_ready(struct tevent_req *req); /* a composite function that does a full SPNEGO session setup @@ -131,18 +137,15 @@ struct tevent_req *smb2_session_setup_spnego_send( struct cli_credentials *credentials, uint64_t previous_session_id) { + struct smb2_transport *transport = session->transport; struct tevent_req *req; struct smb2_session_setup_spnego_state *state; uint64_t current_session_id; const char *chosen_oid; - struct tevent_req *subreq; NTSTATUS status; const DATA_BLOB *server_gss_blob; - DATA_BLOB negprot_secblob = data_blob_null; - uint32_t timeout_msec; - uint8_t in_flags = 0; - - timeout_msec = session->transport->options.request_timeout * 1000; + struct timeval endtime; + bool ok; req = tevent_req_create(mem_ctx, &state, struct smb2_session_setup_spnego_state); @@ -153,6 +156,16 @@ struct tevent_req *smb2_session_setup_spnego_send( state->session = session; state->credentials = credentials; state->previous_session_id = previous_session_id; + state->gensec_status = NT_STATUS_MORE_PROCESSING_REQUIRED; + state->remote_status = NT_STATUS_MORE_PROCESSING_REQUIRED; + + endtime = timeval_current_ofs(transport->options.request_timeout, 0); + + ok = tevent_req_set_endtime(req, ev, endtime); + if (!ok) { + tevent_req_oom(req); + return tevent_req_post(req, ev); + } current_session_id = smb2cli_session_current_id(state->session->smbXcli); if (state->session->needs_bind) { @@ -162,7 +175,7 @@ struct tevent_req *smb2_session_setup_spnego_send( } server_gss_blob = smbXcli_conn_server_gss_blob(session->transport->conn); if (server_gss_blob) { - negprot_secblob = *server_gss_blob; + state->out_secblob = *server_gss_blob; } status = gensec_set_credentials(session->gensec, credentials); @@ -181,7 +194,7 @@ struct tevent_req *smb2_session_setup_spnego_send( return tevent_req_post(req, ev); } - if (negprot_secblob.length > 0) { + if (state->out_secblob.length > 0) { chosen_oid = GENSEC_OID_SPNEGO; } else { chosen_oid = GENSEC_OID_NTLMSSP; @@ -192,15 +205,83 @@ struct tevent_req *smb2_session_setup_spnego_send( return tevent_req_post(req, ev); } - status = gensec_update_ev(session->gensec, state, - state->ev, - negprot_secblob, - &state->in_secblob); - if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - tevent_req_nterror(req, status); + smb2_session_setup_spnego_gensec_next(req); + if (!tevent_req_is_in_progress(req)) { return tevent_req_post(req, ev); } + + return req; +} + +static void smb2_session_setup_spnego_gensec_next(struct tevent_req *req) +{ + struct smb2_session_setup_spnego_state *state = + tevent_req_data(req, + struct smb2_session_setup_spnego_state); + struct smb2_session *session = state->session; + struct tevent_req *subreq = NULL; + + if (NT_STATUS_IS_OK(state->gensec_status)) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + + subreq = gensec_update_send(state, state->ev, + session->gensec, + state->out_secblob); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, + smb2_session_setup_spnego_gensec_done, + req); +} + +static void smb2_session_setup_spnego_gensec_done(struct tevent_req *subreq) +{ + struct tevent_req *req = + tevent_req_callback_data(subreq, + struct tevent_req); + struct smb2_session_setup_spnego_state *state = + tevent_req_data(req, + struct smb2_session_setup_spnego_state); + NTSTATUS status; + + status = gensec_update_recv(subreq, state, + &state->in_secblob); state->gensec_status = status; + state->out_secblob = data_blob_null; + if (!NT_STATUS_IS_OK(status) && + !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + tevent_req_nterror(req, status); + return; + } + + if (NT_STATUS_IS_OK(state->remote_status) && + NT_STATUS_IS_OK(state->gensec_status)) { + smb2_session_setup_spnego_both_ready(req); + return; + } + + smb2_session_setup_spnego_smb2_next(req); +} + +static void smb2_session_setup_spnego_smb2_next(struct tevent_req *req) +{ + struct smb2_session_setup_spnego_state *state = + tevent_req_data(req, + struct smb2_session_setup_spnego_state); + struct smb2_session *session = state->session; + uint32_t timeout_msec; + uint8_t in_flags = 0; + struct tevent_req *subreq = NULL; + + if (NT_STATUS_IS_OK(state->remote_status)) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + + timeout_msec = session->transport->options.request_timeout * 1000; if (state->session_bind) { in_flags |= SMB2_SESSION_FLAG_BINDING; @@ -216,17 +297,17 @@ struct tevent_req *smb2_session_setup_spnego_send( state->previous_session_id, &state->in_secblob); if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); + return; } - tevent_req_set_callback(subreq, smb2_session_setup_spnego_done, req); - - return req; + tevent_req_set_callback(subreq, + smb2_session_setup_spnego_smb2_done, + req); } /* handle continuations of the spnego session setup */ -static void smb2_session_setup_spnego_done(struct tevent_req *subreq) +static void smb2_session_setup_spnego_smb2_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data(subreq, @@ -234,104 +315,90 @@ static void smb2_session_setup_spnego_done(struct tevent_req *subreq) struct smb2_session_setup_spnego_state *state = tevent_req_data(req, struct smb2_session_setup_spnego_state); - struct smb2_session *session = state->session; - NTSTATUS peer_status; NTSTATUS status; - struct iovec *recv_iov; - uint32_t timeout_msec; - uint8_t in_flags = 0; - - timeout_msec = session->transport->options.request_timeout * 1000; status = smb2cli_session_setup_recv(subreq, state, - &recv_iov, + &state->recv_iov, &state->out_secblob); + state->remote_status = status; + state->in_secblob = data_blob_null; if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { tevent_req_nterror(req, status); return; } - peer_status = status; - if (NT_STATUS_EQUAL(state->gensec_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - status = gensec_update_ev(session->gensec, state, - state->ev, - state->out_secblob, - &state->in_secblob); - state->gensec_status = status; - } - - if (!NT_STATUS_IS_OK(status) && - !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - tevent_req_nterror(req, status); + if (NT_STATUS_IS_OK(state->remote_status) && + NT_STATUS_IS_OK(state->gensec_status)) { + smb2_session_setup_spnego_both_ready(req); return; } - if (NT_STATUS_IS_OK(peer_status) && NT_STATUS_IS_OK(state->gensec_status)) { - DATA_BLOB session_key; + smb2_session_setup_spnego_gensec_next(req); +} - if (state->reauth) { - tevent_req_done(req); - return; - } +static void smb2_session_setup_spnego_both_ready(struct tevent_req *req) +{ + struct smb2_session_setup_spnego_state *state = + tevent_req_data(req, + struct smb2_session_setup_spnego_state); + struct smb2_session *session = state->session; + NTSTATUS status; + DATA_BLOB session_key; - if (cli_credentials_is_anonymous(state->credentials)) { - /* - * Windows server does not set the - * SMB2_SESSION_FLAG_IS_GUEST nor - * SMB2_SESSION_FLAG_IS_NULL flag. - * - * This fix makes sure we do not try - * to verify a signature on the final - * session setup response. - */ - tevent_req_done(req); - return; - } + if (state->out_secblob.length != 0) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } - status = gensec_session_key(session->gensec, state, - &session_key); - if (tevent_req_nterror(req, status)) { - return; - } + if (state->in_secblob.length != 0) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } - if (state->session_bind) { - status = smb2cli_session_set_channel_key(session->smbXcli, - session_key, - recv_iov); - if (tevent_req_nterror(req, status)) { - return; - } - session->needs_bind = false; - } else { - status = smb2cli_session_set_session_key(session->smbXcli, - session_key, - recv_iov); - if (tevent_req_nterror(req, status)) { - return; - } - } + if (state->reauth) { tevent_req_done(req); return; } - if (state->session_bind) { - in_flags |= SMB2_SESSION_FLAG_BINDING; + if (cli_credentials_is_anonymous(state->credentials)) { + /* + * Windows server does not set the + * SMB2_SESSION_FLAG_IS_GUEST nor + * SMB2_SESSION_FLAG_IS_NULL flag. + * + * This fix makes sure we do not try + * to verify a signature on the final + * session setup response. + */ + tevent_req_done(req); + return; } - subreq = smb2cli_session_setup_send(state, state->ev, - session->transport->conn, - timeout_msec, - session->smbXcli, - in_flags, - 0, /* in_capabilities */ - 0, /* in_channel */ - state->previous_session_id, - &state->in_secblob); - if (tevent_req_nomem(subreq, req)) { + status = gensec_session_key(session->gensec, state, + &session_key); + if (tevent_req_nterror(req, status)) { return; } - tevent_req_set_callback(subreq, smb2_session_setup_spnego_done, req); + + if (state->session_bind) { + status = smb2cli_session_set_channel_key(session->smbXcli, + session_key, + state->recv_iov); + if (tevent_req_nterror(req, status)) { + return; + } + session->needs_bind = false; + } else { + status = smb2cli_session_set_session_key(session->smbXcli, + session_key, + state->recv_iov); + if (tevent_req_nterror(req, status)) { + return; + } + } + tevent_req_done(req); + return; } /* |