summaryrefslogtreecommitdiff
path: root/source4/libcli
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2017-05-15 23:37:22 +0200
committerAndrew Bartlett <abartlet@samba.org>2017-05-21 21:05:13 +0200
commit3c2e02968e687a96cae30ba13d69205644f12dac (patch)
treec68d6788693ee7c303b8be6d2eaae4f627534658 /source4/libcli
parent2c3e99d1697b83f7dd498596a274fe2e8e96116d (diff)
downloadsamba-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')
-rw-r--r--source4/libcli/smb2/session.c253
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;
}
/*