summaryrefslogtreecommitdiff
path: root/libcli
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2015-05-29 15:29:31 +0200
committerStefan Metzmacher <metze@samba.org>2015-06-12 17:08:18 +0200
commit59338434274799db1ac60b082a6453bd924c5f4c (patch)
treeb0306413f40dac85f32ab057e19b6e8834bda0be /libcli
parent8f42df235dc825a103631fdf0e37e1c1d03cf420 (diff)
downloadsamba-59338434274799db1ac60b082a6453bd924c5f4c.tar.gz
libcli/smb: make sure the writev_send of smbXcli_conn_samba_suicide() is removed before closing the socket
BUG: https://bugzilla.samba.org/show_bug.cgi?id=11316 Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Volker Lendecke <vl@samba.org>
Diffstat (limited to 'libcli')
-rw-r--r--libcli/smb/smbXcli_base.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
index 63bcee9f600..43642e799c4 100644
--- a/libcli/smb/smbXcli_base.c
+++ b/libcli/smb/smbXcli_base.c
@@ -52,6 +52,7 @@ struct smbXcli_conn {
struct tevent_queue *outgoing;
struct tevent_req **pending;
struct tevent_req *read_smb_req;
+ struct tevent_req *suicide_req;
enum protocol_types min_protocol;
enum protocol_types max_protocol;
@@ -520,8 +521,11 @@ struct smbXcli_conn_samba_suicide_state {
struct smbXcli_conn *conn;
struct iovec iov;
uint8_t buf[9];
+ struct tevent_req *write_req;
};
+static void smbXcli_conn_samba_suicide_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state);
static void smbXcli_conn_samba_suicide_done(struct tevent_req *subreq);
struct tevent_req *smbXcli_conn_samba_suicide_send(TALLOC_CTX *mem_ctx,
@@ -542,6 +546,11 @@ struct tevent_req *smbXcli_conn_samba_suicide_send(TALLOC_CTX *mem_ctx,
SCVAL(state->buf, 8, exitcode);
_smb_setlen_nbt(state->buf, sizeof(state->buf)-4);
+ if (conn->suicide_req != NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
state->iov.iov_base = state->buf;
state->iov.iov_len = sizeof(state->buf);
@@ -551,9 +560,39 @@ struct tevent_req *smbXcli_conn_samba_suicide_send(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
tevent_req_set_callback(subreq, smbXcli_conn_samba_suicide_done, req);
+ state->write_req = subreq;
+
+ tevent_req_set_cleanup_fn(req, smbXcli_conn_samba_suicide_cleanup);
+
+ /*
+ * We need to use tevent_req_defer_callback()
+ * in order to allow smbXcli_conn_disconnect()
+ * to do a safe cleanup.
+ */
+ tevent_req_defer_callback(req, ev);
+ conn->suicide_req = req;
+
return req;
}
+static void smbXcli_conn_samba_suicide_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state)
+{
+ struct smbXcli_conn_samba_suicide_state *state = tevent_req_data(
+ req, struct smbXcli_conn_samba_suicide_state);
+
+ TALLOC_FREE(state->write_req);
+
+ if (state->conn == NULL) {
+ return;
+ }
+
+ if (state->conn->suicide_req == req) {
+ state->conn->suicide_req = NULL;
+ }
+ state->conn = NULL;
+}
+
static void smbXcli_conn_samba_suicide_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
@@ -563,9 +602,12 @@ static void smbXcli_conn_samba_suicide_done(struct tevent_req *subreq)
ssize_t nwritten;
int err;
+ state->write_req = NULL;
+
nwritten = writev_recv(subreq, &err);
TALLOC_FREE(subreq);
if (nwritten == -1) {
+ /* here, we need to notify all pending requests */
NTSTATUS status = map_nt_error_from_unix_common(err);
smbXcli_conn_disconnect(state->conn, status);
return;
@@ -1006,6 +1048,17 @@ void smbXcli_conn_disconnect(struct smbXcli_conn *conn, NTSTATUS status)
smb2cli_session_increment_channel_sequence(session);
}
+ if (conn->suicide_req != NULL) {
+ /*
+ * smbXcli_conn_samba_suicide_send()
+ * used tevent_req_defer_callback() already.
+ */
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(conn->suicide_req, status);
+ }
+ conn->suicide_req = NULL;
+ }
+
/*
* Cancel all pending requests. We do not do a for-loop walking
* conn->pending because that array changes in