[PATCH] Fix libsmbclient - allow SMBC_ftruncate_ctx() to work over SMB2

Jeremy Allison jra at samba.org
Wed Jan 4 00:13:57 UTC 2017


Fix for bug:

https://bugzilla.samba.org/show_bug.cgi?id=12479

Fix confirmed by submitter (Paul). Adds torture
test to ensure we don't regress.

Please review and push if happy !

Thanks,

	Jeremy.
-------------- next part --------------
From 2576601c70a5b06f0960a61258355c003999d307 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Wed, 21 Dec 2016 13:55:50 -0800
Subject: [PATCH 1/2] s3: libsmb: Add cli_smb2_ftruncate(), plumb into
 cli_ftruncate().

BUG: https://bugzilla.samba.org/show_bug.cgi?id=12479

Signed-off-by: Jeremy Allison <jra at samba.org>
---
 source3/libsmb/cli_smb2_fnum.c | 65 ++++++++++++++++++++++++++++++++++++++++++
 source3/libsmb/cli_smb2_fnum.h |  3 ++
 source3/libsmb/clifile.c       |  8 +++++-
 3 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index 266f2d32fd7..848e077162c 100644
--- a/source3/libsmb/cli_smb2_fnum.c
+++ b/source3/libsmb/cli_smb2_fnum.c
@@ -3574,3 +3574,68 @@ NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
 	TALLOC_FREE(frame);
 	return status;
 }
+
+/***************************************************************
+ Wrapper that allows SMB2 to truncate a file.
+ Synchronous only.
+***************************************************************/
+
+NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
+			uint16_t fnum,
+			uint64_t newsize)
+{
+	NTSTATUS status;
+	DATA_BLOB inbuf = data_blob_null;
+	struct smb2_hnd *ph = NULL;
+	TALLOC_CTX *frame = talloc_stackframe();
+
+	if (smbXcli_conn_has_async_calls(cli->conn)) {
+		/*
+		 * Can't use sync call while an async call is in flight
+		 */
+		status = NT_STATUS_INVALID_PARAMETER;
+		goto fail;
+	}
+
+	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
+		status = NT_STATUS_INVALID_PARAMETER;
+		goto fail;
+	}
+
+	status = map_fnum_to_smb2_handle(cli,
+					fnum,
+					&ph);
+	if (!NT_STATUS_IS_OK(status)) {
+		goto fail;
+	}
+
+	inbuf = data_blob_talloc_zero(frame, 8);
+	if (inbuf.data == NULL) {
+		status = NT_STATUS_NO_MEMORY;
+		goto fail;
+	}
+
+	SBVAL(inbuf.data, 0, newsize);
+
+	/* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
+	   level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
+
+	status = smb2cli_set_info(cli->conn,
+				cli->timeout,
+				cli->smb2.session,
+				cli->smb2.tcon,
+				1, /* in_info_type */
+					/* in_file_info_class */
+				SMB_FILE_END_OF_FILE_INFORMATION - 1000,
+				&inbuf, /* in_input_buffer */
+				0, /* in_additional_info */
+				ph->fid_persistent,
+				ph->fid_volatile);
+
+  fail:
+
+	cli->raw_status = status;
+
+	TALLOC_FREE(frame);
+	return status;
+}
diff --git a/source3/libsmb/cli_smb2_fnum.h b/source3/libsmb/cli_smb2_fnum.h
index 3289f7e78f4..12c42a270ea 100644
--- a/source3/libsmb/cli_smb2_fnum.h
+++ b/source3/libsmb/cli_smb2_fnum.h
@@ -208,4 +208,7 @@ NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
 			bool get_names,
 			char ***pnames,
 			int *pnum_names);
+NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
+			uint16_t fnum,
+			uint64_t newsize);
 #endif /* __SMB2CLI_FNUM_H__ */
diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c
index 5e667bdca93..03dd6407f60 100644
--- a/source3/libsmb/clifile.c
+++ b/source3/libsmb/clifile.c
@@ -2819,11 +2819,17 @@ NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
 
 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
 {
-	TALLOC_CTX *frame = talloc_stackframe();
+	TALLOC_CTX *frame = NULL;
 	struct tevent_context *ev = NULL;
 	struct tevent_req *req = NULL;
 	NTSTATUS status = NT_STATUS_OK;
 
+	if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+		return cli_smb2_ftruncate(cli, fnum, size);
+	}
+
+	frame = talloc_stackframe();
+
 	if (smbXcli_conn_has_async_calls(cli->conn)) {
 		/*
 		 * Can't use sync call while an async call is in flight
-- 
2.11.0.390.gc69c2f50cf-goog


From 4c795c56753d6259cc5c7bbadbf743adc69eb28b Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Tue, 3 Jan 2017 15:37:03 -0800
Subject: [PATCH 2/2] s3: torture: Add test for cli_ftruncate calling
 cli_smb2_ftruncate.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=12479

Signed-off-by: Jeremy Allison <jra at samba.org>
---
 source3/selftest/tests.py   |   2 +-
 source3/torture/proto.h     |   1 +
 source3/torture/test_smb2.c | 157 ++++++++++++++++++++++++++++++++++++++++++++
 source3/torture/torture.c   |   1 +
 4 files changed, 160 insertions(+), 1 deletion(-)

diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index d9d32cce10e..3aecc9c3e8a 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -53,7 +53,7 @@ tests = ["FDPASS", "LOCK1", "LOCK2", "LOCK3", "LOCK4", "LOCK5", "LOCK6", "LOCK7"
         "CHAIN3", "PIDHIGH",
         "GETADDRINFO", "UID-REGRESSION-TEST", "SHORTNAME-TEST",
         "CASE-INSENSITIVE-CREATE", "SMB2-BASIC", "NTTRANS-FSCTL", "SMB2-NEGPROT",
-        "SMB2-SESSION-REAUTH", "SMB2-SESSION-RECONNECT",
+        "SMB2-SESSION-REAUTH", "SMB2-SESSION-RECONNECT", "SMB2-FTRUNCATE",
         "CLEANUP1",
         "CLEANUP2",
         "CLEANUP4",
diff --git a/source3/torture/proto.h b/source3/torture/proto.h
index 7d2deddd564..da0c69f4f69 100644
--- a/source3/torture/proto.h
+++ b/source3/torture/proto.h
@@ -98,6 +98,7 @@ bool run_smb2_session_reconnect(int dummy);
 bool run_smb2_tcon_dependence(int dummy);
 bool run_smb2_multi_channel(int dummy);
 bool run_smb2_session_reauth(int dummy);
+bool run_smb2_ftruncate(int dummy);
 bool run_chain3(int dummy);
 bool run_local_conv_auth_info(int dummy);
 bool run_local_sprintf_append(int dummy);
diff --git a/source3/torture/test_smb2.c b/source3/torture/test_smb2.c
index 7819bc277fd..c0d11e61087 100644
--- a/source3/torture/test_smb2.c
+++ b/source3/torture/test_smb2.c
@@ -27,6 +27,7 @@
 #include "auth/gensec/gensec.h"
 #include "auth_generic.h"
 #include "../librpc/ndr/libndr.h"
+#include "libsmb/clirap.h"
 
 extern fstring host, workgroup, share, password, username, myname;
 extern struct cli_credentials *torture_creds;
@@ -1892,3 +1893,159 @@ bool run_smb2_session_reauth(int dummy)
 
 	return true;
 }
+
+static NTSTATUS check_size(struct cli_state *cli,
+				uint16_t fnum,
+				const char *fname,
+				size_t size)
+{
+	off_t size_read = 0;
+
+	NTSTATUS status = cli_qfileinfo_basic(cli,
+				fnum,
+				NULL,
+				&size_read,
+				NULL,
+				NULL,
+				NULL,
+				NULL,
+				NULL);
+
+	if (!NT_STATUS_IS_OK(status)) {
+		printf("cli_smb2_qfileinfo_basic of %s failed (%s)\n",
+			fname,
+			nt_errstr(status));
+		return status;
+	}
+
+	if (size != size_read) {
+		printf("size (%u) != size_read(%u) for %s\n",
+			(unsigned int)size,
+			(unsigned int)size_read,
+			fname);
+		/* Use EOF to mean bad size. */
+		return NT_STATUS_END_OF_FILE;
+	}
+	return NT_STATUS_OK;
+}
+
+/* Ensure cli_ftruncate() works for SMB2. */
+
+bool run_smb2_ftruncate(int dummy)
+{
+	struct cli_state *cli = NULL;
+	const char *fname = "smb2_ftruncate.txt";
+	uint16_t fnum = (uint16_t)-1;
+	bool correct = false;
+	size_t buflen = 1024*1024;
+	uint8_t *buf = NULL;
+	unsigned int i;
+	NTSTATUS status;
+
+	printf("Starting SMB2-FTRUNCATE\n");
+
+	if (!torture_init_connection(&cli)) {
+		goto fail;
+	}
+
+	status = smbXcli_negprot(cli->conn, cli->timeout,
+				 PROTOCOL_SMB2_02, PROTOCOL_SMB2_02);
+	if (!NT_STATUS_IS_OK(status)) {
+		printf("smbXcli_negprot returned %s\n", nt_errstr(status));
+		goto fail;
+	}
+
+	status = cli_session_setup_creds(cli, torture_creds);
+	if (!NT_STATUS_IS_OK(status)) {
+		printf("cli_session_setup returned %s\n", nt_errstr(status));
+		goto fail;
+	}
+
+	status = cli_tree_connect(cli, share, "?????", NULL);
+	if (!NT_STATUS_IS_OK(status)) {
+		printf("cli_tree_connect returned %s\n", nt_errstr(status));
+		goto fail;
+	}
+
+	cli_setatr(cli, fname, 0, 0);
+	cli_unlink(cli, fname, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
+
+	status = cli_ntcreate(cli,
+				fname,
+				0,
+				GENERIC_ALL_ACCESS,
+				FILE_ATTRIBUTE_NORMAL,
+				FILE_SHARE_NONE,
+				FILE_CREATE,
+				0,
+				0,
+				&fnum,
+				NULL);
+
+        if (!NT_STATUS_IS_OK(status)) {
+                printf("open of %s failed (%s)\n", fname, nt_errstr(status));
+                goto fail;
+        }
+
+	buf = talloc_zero_array(cli, uint8_t, buflen);
+	if (buf == NULL) {
+		goto fail;
+	}
+
+	/* Write 1MB. */
+	status = cli_writeall(cli,
+				fnum,
+				0,
+				buf,
+				0,
+				buflen,
+				NULL);
+
+	if (!NT_STATUS_IS_OK(status)) {
+		printf("write of %u to %s failed (%s)\n",
+			(unsigned int)buflen,
+			fname,
+			nt_errstr(status));
+		goto fail;
+	}
+
+	status = check_size(cli, fnum, fname, buflen);
+	if (!NT_STATUS_IS_OK(status)) {
+		goto fail;
+	}
+
+	/* Now ftruncate. */
+	for ( i = 0; i < 10; i++) {
+		status = cli_ftruncate(cli, fnum, i*1024);
+		if (!NT_STATUS_IS_OK(status)) {
+			printf("cli_ftruncate %u of %s failed (%s)\n",
+				(unsigned int)i*1024,
+				fname,
+				nt_errstr(status));
+			goto fail;
+		}
+		status = check_size(cli, fnum, fname, i*1024);
+		if (!NT_STATUS_IS_OK(status)) {
+			goto fail;
+		}
+	}
+
+	correct = true;
+
+  fail:
+
+	if (cli == NULL) {
+		return false;
+	}
+
+	if (fnum != (uint16_t)-1) {
+		cli_close(cli, fnum);
+	}
+	cli_setatr(cli, fname, 0, 0);
+	cli_unlink(cli, fname, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
+
+	if (!torture_close_connection(cli)) {
+		correct = false;
+	}
+	return correct;
+}
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 1a57f41e277..ff3d68ecba7 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -11070,6 +11070,7 @@ static struct {
 	{ "SMB2-TCON-DEPENDENCE", run_smb2_tcon_dependence },
 	{ "SMB2-MULTI-CHANNEL", run_smb2_multi_channel },
 	{ "SMB2-SESSION-REAUTH", run_smb2_session_reauth },
+	{ "SMB2-FTRUNCATE", run_smb2_ftruncate },
 	{ "CLEANUP1", run_cleanup1 },
 	{ "CLEANUP2", run_cleanup2 },
 	{ "CLEANUP3", run_cleanup3 },
-- 
2.11.0.390.gc69c2f50cf-goog



More information about the samba-technical mailing list