From 7f9cdad58b92fba40cb2d2b184b1a363f650f15d Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 6 Jun 2011 11:32:44 +0200 Subject: [PATCH 1/2] s3: Fix 8197 --- source3/include/client.h | 1 + source3/libsmb/async_smb.c | 41 ++++++++++++++++++++++------------------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/source3/include/client.h b/source3/include/client.h index 7d66bf9..858182c 100644 --- a/source3/include/client.h +++ b/source3/include/client.h @@ -148,6 +148,7 @@ struct cli_state { struct tevent_queue *outgoing; struct tevent_req **pending; + struct tevent_req *read_smb_req; }; struct file_info { diff --git a/source3/libsmb/async_smb.c b/source3/libsmb/async_smb.c index 2ce6410..8395c80 100644 --- a/source3/libsmb/async_smb.c +++ b/source3/libsmb/async_smb.c @@ -154,12 +154,8 @@ void cli_smb_req_unset_pending(struct tevent_req *req) int i; if (num_pending == 1) { - /* - * The pending read_smb tevent_req is a child of - * cli->pending. So if nothing is pending anymore, we need to - * delete the socket read fde. - */ TALLOC_FREE(cli->pending); + cli->read_smb_req = NULL; return; } @@ -206,7 +202,6 @@ bool cli_smb_req_set_pending(struct tevent_req *req) struct cli_state *cli; struct tevent_req **pending; int num_pending; - struct tevent_req *subreq; cli = state->cli; num_pending = talloc_array_length(cli->pending); @@ -220,7 +215,7 @@ bool cli_smb_req_set_pending(struct tevent_req *req) cli->pending = pending; talloc_set_destructor(req, cli_smb_req_destructor); - if (num_pending > 0) { + if (cli->read_smb_req != NULL) { return true; } @@ -228,12 +223,12 @@ bool cli_smb_req_set_pending(struct tevent_req *req) * We're the first ones, add the read_smb request that waits for the * answer from the server */ - subreq = read_smb_send(cli->pending, state->ev, cli->fd); - if (subreq == NULL) { + cli->read_smb_req = read_smb_send(cli, state->ev, cli->fd); + if (cli->read_smb_req == NULL) { cli_smb_req_unset_pending(req); return false; } - tevent_req_set_callback(subreq, cli_smb_received, cli); + tevent_req_set_callback(cli->read_smb_req, cli_smb_received, cli); return true; } @@ -435,6 +430,12 @@ static NTSTATUS cli_smb_req_iov_send(struct tevent_req *req, return NT_STATUS_NO_MEMORY; } tevent_req_set_callback(subreq, cli_smb_sent, req); + + if (!cli_smb_req_set_pending(req)) { + TALLOC_FREE(subreq); + return NT_STATUS_NO_MEMORY; + } + return NT_STATUS_OK; } @@ -501,22 +502,19 @@ static void cli_smb_sent(struct tevent_req *subreq) case SMBtranss2: case SMBnttranss: case SMBntcancel: + cli_smb_req_unset_pending(req); state->inbuf = NULL; tevent_req_done(req); return; case SMBlockingX: if ((CVAL(state->header, smb_wct) == 8) && (CVAL(state->vwv+3, 0) == LOCKING_ANDX_OPLOCK_RELEASE)) { + cli_smb_req_unset_pending(req); state->inbuf = NULL; tevent_req_done(req); return; } } - - if (!cli_smb_req_set_pending(req)) { - tevent_req_nterror(req, NT_STATUS_NO_MEMORY); - return; - } } static void cli_smb_received(struct tevent_req *subreq) @@ -535,6 +533,7 @@ static void cli_smb_received(struct tevent_req *subreq) received = read_smb_recv(subreq, talloc_tos(), &inbuf, &err); TALLOC_FREE(subreq); + cli->read_smb_req = NULL; if (received == -1) { if (cli->fd != -1) { close(cli->fd); @@ -614,6 +613,8 @@ static void cli_smb_received(struct tevent_req *subreq) req = cli->pending[i]; state = tevent_req_data(req, struct cli_smb_state); + cli_smb_req_unset_pending(req); + if (!oplock_break /* oplock breaks are not signed */ && !cli_check_sign_mac(cli, (char *)inbuf, state->seqnum+1)) { DEBUG(10, ("cli_check_sign_mac failed\n")); @@ -648,18 +649,20 @@ static void cli_smb_received(struct tevent_req *subreq) TALLOC_FREE(chain); } done: - if (talloc_array_length(cli->pending) > 0) { + if ((talloc_array_length(cli->pending) > 0) && + (cli->read_smb_req == NULL)) { /* * Set up another read request for the other pending cli_smb * requests */ state = tevent_req_data(cli->pending[0], struct cli_smb_state); - subreq = read_smb_send(cli->pending, state->ev, cli->fd); - if (subreq == NULL) { + cli->read_smb_req = read_smb_send(cli, state->ev, cli->fd); + if (cli->read_smb_req == NULL) { status = NT_STATUS_NO_MEMORY; goto fail; } - tevent_req_set_callback(subreq, cli_smb_received, cli); + tevent_req_set_callback(cli->read_smb_req, cli_smb_received, + cli); } return; fail: -- 1.7.3.4 From 02e4c7b941adaff5a774dfef4b3cac14f2409a3d Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 7 Jun 2011 14:33:39 +0200 Subject: [PATCH 2/2] s3: In cli_smb_received we now potentially call unset_pending twice Make sure that we don't delete the pending read_smb_req if there are still requests outstanding --- source3/libsmb/async_smb.c | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/source3/libsmb/async_smb.c b/source3/libsmb/async_smb.c index 8395c80..fc737a1 100644 --- a/source3/libsmb/async_smb.c +++ b/source3/libsmb/async_smb.c @@ -153,12 +153,6 @@ void cli_smb_req_unset_pending(struct tevent_req *req) int num_pending = talloc_array_length(cli->pending); int i; - if (num_pending == 1) { - TALLOC_FREE(cli->pending); - cli->read_smb_req = NULL; - return; - } - for (i=0; ipending[i]) { break; @@ -173,6 +167,12 @@ void cli_smb_req_unset_pending(struct tevent_req *req) return; } + if (num_pending == 1) { + TALLOC_FREE(cli->pending); + cli->read_smb_req = NULL; + return; + } + /* * Remove ourselves from the cli->pending array */ -- 1.7.3.4