From 8b75cbb89161d444bf55e1959ba1b38381abd466 Mon Sep 17 00:00:00 2001 From: Jeremy Allison 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 Reviewed-by: Uri Simchoni (cherry picked from commit e0f1ed9f450851bf5b7fec84577b50047309db3f) --- 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 876eb148af9..f51a39ceb84 100644 --- a/source3/libsmb/cli_smb2_fnum.c +++ b/source3/libsmb/cli_smb2_fnum.c @@ -3143,3 +3143,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 0436c68da8b..d8a517c30ee 100644 --- a/source3/libsmb/cli_smb2_fnum.h +++ b/source3/libsmb/cli_smb2_fnum.h @@ -190,4 +190,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 fca7c9150fd..b8cdbca2f2d 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -2946,11 +2946,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 5fd406323517359057a396d85e749950efa3e12e Mon Sep 17 00:00:00 2001 From: Jeremy Allison 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 Back-port from cherry pick from commit b92cac857823ac2d29133fba2fde57cf58805b45) Signed-off-by: Jeremy Allison Reviewed-by: Uri Simchoni --- source3/selftest/tests.py | 2 +- source3/torture/proto.h | 1 + source3/torture/test_smb2.c | 160 ++++++++++++++++++++++++++++++++++++++++++++ source3/torture/torture.c | 1 + 4 files changed, 163 insertions(+), 1 deletion(-) diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 9a2d5869b39..d80750ec162 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 fc7c33f2d23..32ad8231b49 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 6871f4c2272..4db8c772b53 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; @@ -1961,3 +1962,162 @@ 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)) { + return false; + } + + 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)); + return false; + } + + status = cli_session_setup(cli, username, + password, strlen(password), + password, strlen(password), + workgroup); + if (!NT_STATUS_IS_OK(status)) { + printf("cli_session_setup returned %s\n", nt_errstr(status)); + return false; + } + + status = cli_tree_connect(cli, share, "?????", "", 0); + if (!NT_STATUS_IS_OK(status)) { + printf("cli_tree_connect returned %s\n", nt_errstr(status)); + return false; + } + + 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 c978741fae7..5eaba162629 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -11074,6 +11074,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