[PATCH] Fix smbclient "notify" command

Volker Lendecke Volker.Lendecke at SerNet.DE
Wed Apr 4 11:12:45 UTC 2018


Hi!

smbclient's "notify" command is pretty broken right now, in particular
it fails badly for smb2. The attached patch fixes it, with
confirmation of a user that I did it for.

Review appreciated!

Thanks, Volker

-- 
SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
phone: +49-551-370000-0, fax: +49-551-370000-9
AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
http://www.sernet.de, mailto:kontakt at sernet.de
-------------- next part --------------
From 4342d64ab66e7ef4667b10a2b9dcc02c9cd32c72 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 30 Oct 2017 14:34:12 +0100
Subject: [PATCH 1/3] libsmb: Handle long-running smb2cli_notify

This likely runs into a timeout. Properly cancel the smb2 request,
allowing the higher-level caller to re-issue this request on an existing
handle.

I did not see a proper way to achieve this with tevent_req_set_endtime or
something like that.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 libcli/smb/smb2cli_notify.c | 54 +++++++++++++++++++++++++++++++++++++--------
 1 file changed, 45 insertions(+), 9 deletions(-)

diff --git a/libcli/smb/smb2cli_notify.c b/libcli/smb/smb2cli_notify.c
index 0a23cf9ad03..34329ba16cc 100644
--- a/libcli/smb/smb2cli_notify.c
+++ b/libcli/smb/smb2cli_notify.c
@@ -30,9 +30,12 @@ struct smb2cli_notify_state {
 	struct iovec *recv_iov;
 	uint8_t *data;
 	uint32_t data_length;
+
+	struct tevent_req *subreq;
 };
 
 static void smb2cli_notify_done(struct tevent_req *subreq);
+static void smb2cli_notify_timedout(struct tevent_req *subreq);
 
 struct tevent_req *smb2cli_notify_send(TALLOC_CTX *mem_ctx,
 				       struct tevent_context *ev,
@@ -64,21 +67,50 @@ struct tevent_req *smb2cli_notify_send(TALLOC_CTX *mem_ctx,
 	SIVAL(fixed, 24, completion_filter);
 	SIVAL(fixed, 28, 0); 	/* reserved */
 
-	subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_NOTIFY,
-				  0, 0, /* flags */
-				  timeout_msec,
-				  tcon,
-				  session,
-				  state->fixed, sizeof(state->fixed),
-				  NULL, 0, /* dyn* */
-				  0); /* max_dyn_len */
+	state->subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_NOTIFY,
+					 0, 0, /* flags */
+					 0,	/* timeout_msec */
+					 tcon,
+					 session,
+					 state->fixed, sizeof(state->fixed),
+					 NULL, 0, /* dyn* */
+					 0); /* max_dyn_len */
+	if (tevent_req_nomem(state->subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(state->subreq, smb2cli_notify_done, req);
+
+	subreq = tevent_wakeup_send(state, ev,
+				    timeval_current_ofs_msec(timeout_msec));
 	if (tevent_req_nomem(subreq, req)) {
 		return tevent_req_post(req, ev);
 	}
-	tevent_req_set_callback(subreq, smb2cli_notify_done, req);
+	tevent_req_set_callback(subreq, smb2cli_notify_timedout, req);
+
 	return req;
 }
 
+static void smb2cli_notify_timedout(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct smb2cli_notify_state *state = tevent_req_data(
+		req, struct smb2cli_notify_state);
+	bool ok;
+
+	ok = tevent_wakeup_recv(subreq);
+	if (!ok) {
+		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+		return;
+	}
+
+	ok = tevent_req_cancel(state->subreq);
+	if (!ok) {
+		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+		return;
+	}
+}
+
 static void smb2cli_notify_done(struct tevent_req *subreq)
 {
 	struct tevent_req *req = tevent_req_callback_data(
@@ -98,6 +130,10 @@ static void smb2cli_notify_done(struct tevent_req *subreq)
 	status = smb2cli_req_recv(subreq, state, &iov,
 				  expected, ARRAY_SIZE(expected));
 	TALLOC_FREE(subreq);
+
+	if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) {
+		status = NT_STATUS_IO_TIMEOUT;
+	}
 	if (tevent_req_nterror(req, status)) {
 		return;
 	}
-- 
2.11.0


From 557d063fd8ed66c20b5efd21437bfc04ce926198 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 30 Oct 2017 14:36:46 +0100
Subject: [PATCH 2/3] libsmb: Handle IO_TIMEOUT in cli_smb2_notify properly

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/libsmb/cli_smb2_fnum.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index 2d87b58d730..c397b29b381 100644
--- a/source3/libsmb/cli_smb2_fnum.c
+++ b/source3/libsmb/cli_smb2_fnum.c
@@ -4192,6 +4192,15 @@ NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
 				completion_filter, recursive,
 				frame, &base, &len);
 
+	if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+		len = 0;
+		status = NT_STATUS_OK;
+	}
+
+	if (!NT_STATUS_IS_OK(status)) {
+		goto fail;
+	}
+
 	ofs = 0;
 
 	while (len - ofs >= 12) {
-- 
2.11.0


From 4e194811e1b0dcec49a2a837bbb17a501f6dbd14 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 30 Oct 2017 16:15:03 +0100
Subject: [PATCH 3/3] smbclient: Handle ENUM_DIR in "notify" command

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/client/client.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/source3/client/client.c b/source3/client/client.c
index 23ed02d9cc0..1429b44e9cf 100644
--- a/source3/client/client.c
+++ b/source3/client/client.c
@@ -4568,12 +4568,17 @@ static int cmd_notify(void)
 	}
 
 	while (1) {
-		uint32_t i, num_changes;
-		struct notify_change *changes;
+		uint32_t i;
+		uint32_t num_changes = 0;
+		struct notify_change *changes = NULL;
 
 		status = cli_notify(cli, fnum, 1000, FILE_NOTIFY_CHANGE_ALL,
 				    true,
 				    talloc_tos(), &num_changes, &changes);
+		if (NT_STATUS_EQUAL(status, STATUS_NOTIFY_ENUM_DIR)) {
+			printf("NOTIFY_ENUM_DIR\n");
+			status = NT_STATUS_OK;
+		}
 		if (!NT_STATUS_IS_OK(status)) {
 			d_printf("notify returned %s\n",
 				 nt_errstr(status));
-- 
2.11.0



More information about the samba-technical mailing list