[PATCH] Two dependent bugfixes for VSS bugs 13455 and 13688
Ralph Böhme
slow at samba.org
Sat Nov 24 10:57:38 UTC 2018
On Fri, Nov 23, 2018 at 01:50:09PM -0800, Jeremy Allison wrote:
>On Fri, Nov 23, 2018 at 09:00:57PM +0100, Ralph Böhme wrote:
>> On Fri, Nov 23, 2018 at 12:53:02PM -0800, Jeremy Allison wrote:
>> > On Fri, Nov 23, 2018 at 12:45:47PM -0800, Jeremy Allison via samba-technical wrote:
>> > > Ralph, I thin [PATCH 09/10] s3:smbd: GMT token handling on paths: prefix, don't append
>> > > is incorrect.
>> > >
>> > > We used to do this, but found it breaks pathnames with a MS-DFS
>> > > prefix (such as \\server\share\path).
>> > >
>> > > If you haven't already, please check this code against a
>> > > server set up with MS-DFS pathnames.
>> > >
>> > > If you don't have time before then, let's talk when I'm back in at
>> > > work on Monday.
>> > > >
>> > > > The ':' after "foor" sets stream_started to true, then the '\' after
>> > > > "stream" triggers the error.
>> > > >
>> > > > Fix: prepend the GMT token to the path, that's what we're later doing in
>> > > > canonicalize_snapshot_path() anyway. For the above example that results
>> >
>> > Note that canonicalize_snapshot_path() is called *after* any MS-DFS
>> > processing is done, which is why it's safe to do that there.
>> >
>> > I think the correct fix here is to search in the SMB2 create
>> > code for a ':' character and if found, insert the @GMT token
>> > before that, otherwise append as we're currently doing.
>> >
>> > This will leave the MS-DFS processing working I think.
>>
>> ok, thanks, I'll recheck. This is a real mess! :)
>
>Sorry, yeah. Keeping pathname processing working over
>SMB1/2/3 over MS-DFS and including the SMB1 @GMT-parsing
>is a horrible compatibility matrix.
especially if there are no tests. :)
>Eventually we need to move to parsing the @GMT parsing
>out into the start and adding a timstamp to struct smb_filename
>(this is how Windows does it internally, I'm sure) but
>that's a larger change for another day, I'm afraid :-).
ha!, we could start right away. :)
What about the attached patchset where I'm passing down the timestamp from the
SMB2 layer down to filename_convert_internal() as an extra argument, processing
it there, instead of doing it at the SMB2 layer?
Passes the new tests.
CI: https://gitlab.com/samba-team/devel/samba/pipelines/37759378
-slow
--
Ralph Boehme, Samba Team https://samba.org/
Samba Developer, SerNet GmbH https://sernet.de/en/samba/
GPG-Fingerprint FAE2C6088A24252051C559E4AA1E9B7126399E46
-------------- next part --------------
From e92e99d971c6b80573d0d10122bde7d06cce8b2d Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 23 Nov 2018 10:07:29 +0100
Subject: [PATCH 01/13] vfs_error_inject: add pwrite
Bug: https://bugzilla.samba.org/show_bug.cgi?id=13688
Signed-off-by: Ralph Boehme <slow at samba.org>
---
source3/modules/vfs_error_inject.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/source3/modules/vfs_error_inject.c b/source3/modules/vfs_error_inject.c
index bb5477a449f..9f0a25fb73f 100644
--- a/source3/modules/vfs_error_inject.c
+++ b/source3/modules/vfs_error_inject.c
@@ -88,8 +88,26 @@ static int vfs_error_inject_chdir(vfs_handle_struct *handle,
return SMB_VFS_NEXT_CHDIR(handle, smb_fname);
}
+static ssize_t vfs_error_inject_pwrite(vfs_handle_struct *handle,
+ files_struct *fsp,
+ const void *data,
+ size_t n,
+ off_t offset)
+{
+ int error;
+
+ error = inject_unix_error("pwrite", handle);
+ if (error != 0) {
+ errno = error;
+ return -1;
+ }
+
+ return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
+}
+
static struct vfs_fn_pointers vfs_error_inject_fns = {
.chdir_fn = vfs_error_inject_chdir,
+ .pwrite_fn = vfs_error_inject_pwrite,
};
static_decl_vfs;
--
2.17.2
From ba78a440c9841571254086bb561d63bd485ae2fc Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 23 Nov 2018 10:18:10 +0100
Subject: [PATCH 02/13] vfs_error_inject: add EBADF error
Bug: https://bugzilla.samba.org/show_bug.cgi?id=13688
Signed-off-by: Ralph Boehme <slow at samba.org>
---
source3/modules/vfs_error_inject.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/source3/modules/vfs_error_inject.c b/source3/modules/vfs_error_inject.c
index 9f0a25fb73f..c8c3ea4701f 100644
--- a/source3/modules/vfs_error_inject.c
+++ b/source3/modules/vfs_error_inject.c
@@ -28,6 +28,7 @@ struct unix_error_map {
int error;
} unix_error_map_array[] = {
{ "ESTALE", ESTALE },
+ { "EBADF", EBADF },
};
static int find_unix_error_from_string(const char *err_str)
--
2.17.2
From 33b9a029860c94d791cf5b500109c795e9d5e2ec Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 14 Nov 2018 13:45:11 +0100
Subject: [PATCH 03/13] s4:torture: add a test-suite for VSS
This test will not be run from the main torture test runner in selftest,
as there we don't pass the required arguments 'twrp_file' and
'twrp_snapshot'.
The test needs a carefully prepared environment with provisioned
snapshot data, so the test will be started from a blackbox test
script. That comes next.
Bug: https://bugzilla.samba.org/show_bug.cgi?id=13688
Signed-off-by: Ralph Boehme <slow at samba.org>
---
source4/torture/smb2/create.c | 87 +++++++++++++++++++++++++++++++++++
source4/torture/smb2/smb2.c | 1 +
2 files changed, 88 insertions(+)
diff --git a/source4/torture/smb2/create.c b/source4/torture/smb2/create.c
index ead56eb5c40..68447935bd0 100644
--- a/source4/torture/smb2/create.c
+++ b/source4/torture/smb2/create.c
@@ -1733,6 +1733,82 @@ static bool test_dir_alloc_size(struct torture_context *tctx,
return ret;
}
+static bool test_twrp_write(struct torture_context *tctx, struct smb2_tree *tree)
+{
+ struct smb2_create io;
+ struct smb2_handle h1 = {{0}};
+ NTSTATUS status;
+ bool ret = true;
+ char *p = NULL;
+ struct tm tm;
+ time_t t;
+ uint64_t nttime;
+ const char *file = NULL;
+ const char *snapshot = NULL;
+
+ file = torture_setting_string(tctx, "twrp_file", NULL);
+ if (file == NULL) {
+ torture_skip(tctx, "missing 'twrp_file' option\n");
+ }
+
+ snapshot = torture_setting_string(tctx, "twrp_snapshot", NULL);
+ if (snapshot == NULL) {
+ torture_skip(tctx, "missing 'twrp_snapshot' option\n");
+ }
+
+ torture_comment(tctx, "Testing timewarp (%s) (%s)\n", file, snapshot);
+
+ setenv("TZ", "GMT", 1);
+ p = strptime(snapshot, "@GMT-%Y.%m.%d-%H.%M.%S", &tm);
+ torture_assert_goto(tctx, p != NULL, ret, done, "strptime\n");
+ torture_assert_goto(tctx, *p == '\0', ret, done, "strptime\n");
+
+ t = mktime(&tm);
+ unix_to_nt_time(&nttime, t);
+
+ io = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_READ_DATA,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.fname = file,
+ .in.query_maximal_access = true,
+ .in.timewarp = nttime,
+ };
+
+ status = smb2_create(tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create\n");
+ smb2_util_close(tree, io.out.file.handle);
+
+ ret = io.out.maximal_access & (SEC_FILE_READ_DATA | SEC_FILE_WRITE_DATA);
+ torture_assert_goto(tctx, ret, ret, done, "Bad access\n");
+
+ io = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.fname = file,
+ .in.timewarp = nttime,
+ };
+
+ status = smb2_create(tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create\n");
+ h1 = io.out.file.handle;
+
+ status = smb2_util_write(tree, h1, "123", 0, 3);
+ torture_assert_ntstatus_equal_goto(tctx, status,
+ NT_STATUS_MEDIA_WRITE_PROTECTED,
+ ret, done, "smb2_create\n");
+
+ smb2_util_close(tree, h1);
+
+done:
+ return ret;
+}
+
/*
basic testing of SMB2 read
*/
@@ -1758,3 +1834,14 @@ struct torture_suite *torture_smb2_create_init(TALLOC_CTX *ctx)
return suite;
}
+
+struct torture_suite *torture_smb2_twrp_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite = torture_suite_create(ctx, "twrp");
+
+ torture_suite_add_1smb2_test(suite, "write", test_twrp_write);
+
+ suite->description = talloc_strdup(suite, "SMB2-TWRP tests");
+
+ return suite;
+}
diff --git a/source4/torture/smb2/smb2.c b/source4/torture/smb2/smb2.c
index 6f9884e3c27..a835dc7c050 100644
--- a/source4/torture/smb2/smb2.c
+++ b/source4/torture/smb2/smb2.c
@@ -154,6 +154,7 @@ NTSTATUS torture_smb2_init(TALLOC_CTX *ctx)
torture_suite_add_suite(suite, torture_smb2_read_init(suite));
torture_suite_add_suite(suite, torture_smb2_aio_delay_init(suite));
torture_suite_add_suite(suite, torture_smb2_create_init(suite));
+ torture_suite_add_suite(suite, torture_smb2_twrp_init(suite));
torture_suite_add_suite(suite, torture_smb2_acls_init(suite));
torture_suite_add_suite(suite, torture_smb2_notify_init(suite));
torture_suite_add_suite(suite, torture_smb2_notify_inotify_init(suite));
--
2.17.2
From 683abec1f938b0ef24e66d0307803c21bdf7abf3 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 23 Nov 2018 10:18:44 +0100
Subject: [PATCH 04/13] s3:script/tests: add a test for VSS write behaviour
Bug: https://bugzilla.samba.org/show_bug.cgi?id=13688
Signed-off-by: Ralph Boehme <slow at samba.org>
---
selftest/knownfail.d/samba3.blackbox | 1 +
selftest/target/Samba3.pm | 9 +++
.../script/tests/test_shadow_copy_torture.sh | 76 +++++++++++++++++++
source3/selftest/tests.py | 3 +-
4 files changed, 88 insertions(+), 1 deletion(-)
create mode 100644 selftest/knownfail.d/samba3.blackbox
create mode 100755 source3/script/tests/test_shadow_copy_torture.sh
diff --git a/selftest/knownfail.d/samba3.blackbox b/selftest/knownfail.d/samba3.blackbox
new file mode 100644
index 00000000000..16537e58aeb
--- /dev/null
+++ b/selftest/knownfail.d/samba3.blackbox
@@ -0,0 +1 @@
+^samba3.blackbox.shadow_copy_torture.writing to shadow copy of a file\(fileserver\)
diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index 363840e4521..0e1ffd1101a 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -2190,6 +2190,15 @@ sub provision($$$$$$$$$)
vfs objects = shadow_copy2
shadow:mountpoint = $shadow_mntdir
wide links = yes
+
+[shadow_write]
+ path = $shadow_tstdir
+ comment = previous versions snapshots under mount point
+ vfs objects = shadow_copy2 error_inject
+ aio write size = 0
+ error_inject:pwrite = EBADF
+ shadow:mountpoint = $shadow_tstdir
+
[dfq]
path = $shrdir/dfree
vfs objects = acl_xattr fake_acls xattr_tdb fake_dfq
diff --git a/source3/script/tests/test_shadow_copy_torture.sh b/source3/script/tests/test_shadow_copy_torture.sh
new file mode 100755
index 00000000000..d47cd512a20
--- /dev/null
+++ b/source3/script/tests/test_shadow_copy_torture.sh
@@ -0,0 +1,76 @@
+#!/bin/bash
+#
+# Blackbox test for shadow_copy2 VFS.
+#
+
+if [ $# -lt 7 ]; then
+cat <<EOF
+Usage: test_shadow_copy SERVER SERVER_IP DOMAIN USERNAME PASSWORD WORKDIR SMBTORTURE
+EOF
+exit 1;
+fi
+
+SERVER=${1}
+SERVER_IP=${2}
+DOMAIN=${3}
+USERNAME=${4}
+PASSWORD=${5}
+WORKDIR=${6}
+SMBTORTURE="$VALGRIND ${7}"
+shift 7
+
+incdir=`dirname $0`/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+SNAPSHOT="@GMT-2015.10.31-19.40.30"
+
+failed=0
+
+# build a hierarchy of files, symlinks, and directories
+build_files()
+{
+ local destdir
+ destdir=$1
+
+ echo "$content" > $destdir/foo
+}
+
+# build a snapshots directory
+build_snapshots()
+{
+ local snapdir
+
+ snapdir=$WORKDIR/.snapshots
+
+ mkdir -p $snapdir
+ mkdir $snapdir/$SNAPSHOT
+
+ build_files $snapdir/$SNAPSHOT
+}
+
+test_shadow_copy_write()
+{
+ local msg
+
+ msg=$1
+
+ #delete snapshots from previous tests
+ find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1
+ build_snapshots
+
+ testit "writing to shadow copy of a file" \
+ $SMBTORTURE \
+ -U$USERNAME%$PASSWORD \
+ "//$SERVER/shadow_write" \
+ --option="torture:twrp_file=foo" \
+ --option="torture:twrp_snapshot=$SNAPSHOT" \
+ smb2.twrp.write || \
+ failed=`expr $failed + 1`
+}
+
+build_files $WORKDIR
+
+# test open for writing and write behaviour of snapshoted files
+test_shadow_copy_write "write behaviour of snapshoted files"
+
+exit $failed
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index f3c5c39664b..bfe875e19fa 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -24,7 +24,7 @@ sys.path.insert(0, os.path.normpath(os.path.join(os.path.dirname(__file__), "../
import selftesthelpers
from selftesthelpers import bindir, srcdir, scriptdir, binpath
from selftesthelpers import plantestsuite, samba3srcdir
-from selftesthelpers import smbtorture3, configuration, smbclient3
+from selftesthelpers import smbtorture3, configuration, smbclient3, smbtorture4
from selftesthelpers import net, wbinfo, dbwrap_tool, rpcclient, python
from selftesthelpers import smbget, smbcacls, smbcquotas, ntlm_auth3
from selftesthelpers import valgrindify, smbtorture4_testsuites
@@ -310,6 +310,7 @@ plantestsuite("samba3.blackbox.smbclient_ntlm.plain (%s)" % env, env, [os.path.j
plantestsuite("samba3.blackbox.offline (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_offline.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/offline', smbclient3])
plantestsuite("samba3.blackbox.shadow_copy2 NT1 (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_shadow_copy.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/shadow', smbclient3, '-m', 'NT1'])
plantestsuite("samba3.blackbox.shadow_copy2 SMB3 (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_shadow_copy.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/shadow', smbclient3, '-m', 'SMB3'])
+ plantestsuite("samba3.blackbox.shadow_copy_torture", env, [os.path.join(samba3srcdir, "script/tests/test_shadow_copy_torture.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/shadow', smbtorture4])
plantestsuite("samba3.blackbox.smbclient.forceuser_validusers (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_forceuser_validusers.sh"), '$SERVER', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH', smbclient3])
plantestsuite("samba3.blackbox.smbget (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_smbget.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', 'smbget_user', '$PASSWORD', '$LOCAL_PATH/smbget', smbget])
plantestsuite("samba3.blackbox.netshareenum (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_shareenum.sh"), '$SERVER', '$USERNAME', '$PASSWORD', rpcclient])
--
2.17.2
From 6a3bc70c7fd272d8dc5ea2ce84484572bc0de21b Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 22 Nov 2018 11:02:24 +0100
Subject: [PATCH 05/13] vfs_shadow_copy2: add _already_converted arg to
shadow_copy2_strip_snapshot_internal()
Not used for now, all existing callers pass NULL.
Bug: https://bugzilla.samba.org/show_bug.cgi?id=13688
Signed-off-by: Ralph Boehme <slow at samba.org>
---
source3/modules/vfs_shadow_copy2.c | 32 ++++++++++++++++++++++--------
1 file changed, 24 insertions(+), 8 deletions(-)
diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c
index 79c1ee5cf33..9d49ce77064 100644
--- a/source3/modules/vfs_shadow_copy2.c
+++ b/source3/modules/vfs_shadow_copy2.c
@@ -587,7 +587,8 @@ static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx,
const char *orig_name,
time_t *ptimestamp,
char **pstripped,
- char **psnappath)
+ char **psnappath,
+ bool *_already_converted)
{
struct tm tm;
time_t timestamp = 0;
@@ -608,6 +609,10 @@ static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx,
DEBUG(10, (__location__ ": enter path '%s'\n", name));
+ if (_already_converted != NULL) {
+ *_already_converted = false;
+ }
+
abs_path = make_path_absolute(mem_ctx, priv, name);
if (abs_path == NULL) {
ret = false;
@@ -630,6 +635,9 @@ static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx,
}
if (already_converted) {
+ if (_already_converted != NULL) {
+ *_already_converted = true;
+ }
goto out;
}
@@ -759,6 +767,7 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx,
orig_name,
ptimestamp,
pstripped,
+ NULL,
NULL);
}
@@ -1119,12 +1128,14 @@ static int shadow_copy2_rename(vfs_handle_struct *handle,
if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle,
smb_fname_src->base_name,
- ×tamp_src, NULL, &snappath_src)) {
+ ×tamp_src, NULL, &snappath_src,
+ NULL)) {
return -1;
}
if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle,
smb_fname_dst->base_name,
- ×tamp_dst, NULL, &snappath_dst)) {
+ ×tamp_dst, NULL, &snappath_dst,
+ NULL)) {
return -1;
}
if (timestamp_src != 0) {
@@ -1163,7 +1174,8 @@ static int shadow_copy2_symlink(vfs_handle_struct *handle,
link_contents,
×tamp_old,
NULL,
- &snappath_old)) {
+ &snappath_old,
+ NULL)) {
return -1;
}
if (!shadow_copy2_strip_snapshot_internal(talloc_tos(),
@@ -1171,7 +1183,8 @@ static int shadow_copy2_symlink(vfs_handle_struct *handle,
new_smb_fname->base_name,
×tamp_new,
NULL,
- &snappath_new)) {
+ &snappath_new,
+ NULL)) {
return -1;
}
if ((timestamp_old != 0) || (timestamp_new != 0)) {
@@ -1202,7 +1215,8 @@ static int shadow_copy2_link(vfs_handle_struct *handle,
old_smb_fname->base_name,
×tamp_old,
NULL,
- &snappath_old)) {
+ &snappath_old,
+ NULL)) {
return -1;
}
if (!shadow_copy2_strip_snapshot_internal(talloc_tos(),
@@ -1210,7 +1224,8 @@ static int shadow_copy2_link(vfs_handle_struct *handle,
new_smb_fname->base_name,
×tamp_new,
NULL,
- &snappath_new)) {
+ &snappath_new,
+ NULL)) {
return -1;
}
if ((timestamp_old != 0) || (timestamp_new != 0)) {
@@ -1566,7 +1581,8 @@ static int shadow_copy2_chdir(vfs_handle_struct *handle,
smb_fname->base_name,
×tamp,
&stripped,
- &snappath)) {
+ &snappath,
+ NULL)) {
return -1;
}
if (stripped != NULL) {
--
2.17.2
From 748827a6cbb8d0270c91ce61deb0b14d91a4e449 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 22 Nov 2018 11:04:54 +0100
Subject: [PATCH 06/13] vfs_shadow_copy2: add
shadow_copy2_strip_snapshot_converted
Can be used by callers to determine if a path is in fact pointing at a
file in a snapshot. Will be used in the next commit.
Bug: https://bugzilla.samba.org/show_bug.cgi?id=13688
Signed-off-by: Ralph Boehme <slow at samba.org>
---
source3/modules/vfs_shadow_copy2.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c
index 9d49ce77064..9d9a84ab4a1 100644
--- a/source3/modules/vfs_shadow_copy2.c
+++ b/source3/modules/vfs_shadow_copy2.c
@@ -771,6 +771,22 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx,
NULL);
}
+static bool shadow_copy2_strip_snapshot_converted(TALLOC_CTX *mem_ctx,
+ struct vfs_handle_struct *handle,
+ const char *orig_name,
+ time_t *ptimestamp,
+ char **pstripped,
+ bool *is_converted)
+{
+ return shadow_copy2_strip_snapshot_internal(mem_ctx,
+ handle,
+ orig_name,
+ ptimestamp,
+ pstripped,
+ NULL,
+ is_converted);
+}
+
static char *shadow_copy2_find_mount_point(TALLOC_CTX *mem_ctx,
vfs_handle_struct *handle)
{
--
2.17.2
From 4eff1c5b846e97ffe28b6b200626a395f3a227e2 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 23 Nov 2018 14:08:15 +0100
Subject: [PATCH 07/13] vfs_shadow_copy2: nicely deal with attempts to open
previous version for writing
Bug: https://bugzilla.samba.org/show_bug.cgi?id=13688
Signed-off-by: Ralph Boehme <slow at samba.org>
---
selftest/knownfail.d/samba3.blackbox | 1 -
source3/modules/vfs_shadow_copy2.c | 124 ++++++++++++++++++++++++++-
2 files changed, 122 insertions(+), 3 deletions(-)
delete mode 100644 selftest/knownfail.d/samba3.blackbox
diff --git a/selftest/knownfail.d/samba3.blackbox b/selftest/knownfail.d/samba3.blackbox
deleted file mode 100644
index 16537e58aeb..00000000000
--- a/selftest/knownfail.d/samba3.blackbox
+++ /dev/null
@@ -1 +0,0 @@
-^samba3.blackbox.shadow_copy_torture.writing to shadow copy of a file\(fileserver\)
diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c
index 9d9a84ab4a1..e105a813e23 100644
--- a/source3/modules/vfs_shadow_copy2.c
+++ b/source3/modules/vfs_shadow_copy2.c
@@ -36,6 +36,8 @@
#include "include/ntioctl.h"
#include "util_tdb.h"
#include "lib/util_path.h"
+#include "libcli/security/security.h"
+#include "lib/util/tevent_unix.h"
struct shadow_copy2_config {
char *gmt_format;
@@ -1376,15 +1378,27 @@ static int shadow_copy2_open(vfs_handle_struct *handle,
time_t timestamp = 0;
char *stripped = NULL;
char *tmp;
+ bool is_converted = false;
int saved_errno = 0;
int ret;
- if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
+ if (!shadow_copy2_strip_snapshot_converted(talloc_tos(), handle,
smb_fname->base_name,
- ×tamp, &stripped)) {
+ ×tamp, &stripped,
+ &is_converted)) {
return -1;
}
if (timestamp == 0) {
+ if (is_converted) {
+ /*
+ * Just pave over the user requested mode and use
+ * O_RDONLY. Later attempts by the client to write on
+ * the handle will fail in the pwrite() syscall with
+ * EINVAL which we carefully map to EROFS. In sum, this
+ * matches Windows behaviour.
+ */
+ flags = O_RDONLY;
+ }
return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
}
@@ -1398,6 +1412,14 @@ static int shadow_copy2_open(vfs_handle_struct *handle,
return -1;
}
+ /*
+ * Just pave over the user requested mode and use O_RDONLY. Later
+ * attempts by the client to write on the handle will fail in the
+ * pwrite() syscall with EINVAL which we carefully map to EROFS. In sum,
+ * this matches Windows behaviour.
+ */
+ flags = O_RDONLY;
+
ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
if (ret == -1) {
saved_errno = errno;
@@ -2887,6 +2909,101 @@ static int shadow_copy2_get_quota(vfs_handle_struct *handle,
return ret;
}
+static ssize_t shadow_copy2_pwrite(vfs_handle_struct *handle,
+ files_struct *fsp,
+ const void *data,
+ size_t n,
+ off_t offset)
+{
+ ssize_t nwritten;
+
+ nwritten = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
+ if (nwritten == -1) {
+ if (errno == EBADF && fsp->can_write) {
+ errno = EROFS;
+ }
+ }
+
+ return nwritten;
+}
+
+struct shadow_copy2_pwrite_state {
+ vfs_handle_struct *handle;
+ files_struct *fsp;
+ ssize_t ret;
+ struct vfs_aio_state vfs_aio_state;
+};
+
+static void shadow_copy2_pwrite_done(struct tevent_req *subreq);
+
+static struct tevent_req *shadow_copy2_pwrite_send(
+ struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev, struct files_struct *fsp,
+ const void *data, size_t n, off_t offset)
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct shadow_copy2_pwrite_state *state = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct shadow_copy2_pwrite_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->handle = handle;
+ state->fsp = fsp;
+
+ subreq = SMB_VFS_NEXT_PWRITE_SEND(state,
+ ev,
+ handle,
+ fsp,
+ data,
+ n,
+ offset);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, shadow_copy2_pwrite_done, req);
+
+ return req;
+}
+
+static void shadow_copy2_pwrite_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct shadow_copy2_pwrite_state *state = tevent_req_data(
+ req, struct shadow_copy2_pwrite_state);
+
+ state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
+ TALLOC_FREE(subreq);
+ if (state->ret == -1) {
+ tevent_req_error(req, state->vfs_aio_state.error);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static ssize_t shadow_copy2_pwrite_recv(struct tevent_req *req,
+ struct vfs_aio_state *vfs_aio_state)
+{
+ struct shadow_copy2_pwrite_state *state = tevent_req_data(
+ req, struct shadow_copy2_pwrite_state);
+
+ if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+ if ((vfs_aio_state->error == EBADF) &&
+ state->fsp->can_write)
+ {
+ vfs_aio_state->error = EROFS;
+ errno = EROFS;
+ }
+ return -1;
+ }
+
+ *vfs_aio_state = state->vfs_aio_state;
+ return state->ret;
+}
+
static int shadow_copy2_connect(struct vfs_handle_struct *handle,
const char *service, const char *user)
{
@@ -3251,6 +3368,9 @@ static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
.setxattr_fn = shadow_copy2_setxattr,
.chflags_fn = shadow_copy2_chflags,
.get_real_filename_fn = shadow_copy2_get_real_filename,
+ .pwrite_fn = shadow_copy2_pwrite,
+ .pwrite_send_fn = shadow_copy2_pwrite_send,
+ .pwrite_recv_fn = shadow_copy2_pwrite_recv,
.connectpath_fn = shadow_copy2_connectpath,
};
--
2.17.2
From 3bfea63dbf83b6c84adfb48f9ce4ec32cb57b2be Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 23 Nov 2018 14:36:56 +0100
Subject: [PATCH 08/13] s3:selftest: add a VSS test reading a stream
Bug: https://bugzilla.samba.org/show_bug.cgi?id=13455
Signed-off-by: Ralph Boehme <slow at samba.org>
---
selftest/knownfail.d/samba3.blackbox | 1 +
selftest/target/Samba3.pm | 2 +-
.../script/tests/test_shadow_copy_torture.sh | 38 ++++++++
source4/torture/smb2/create.c | 87 +++++++++++++++++++
4 files changed, 127 insertions(+), 1 deletion(-)
create mode 100644 selftest/knownfail.d/samba3.blackbox
diff --git a/selftest/knownfail.d/samba3.blackbox b/selftest/knownfail.d/samba3.blackbox
new file mode 100644
index 00000000000..a15359e6420
--- /dev/null
+++ b/selftest/knownfail.d/samba3.blackbox
@@ -0,0 +1 @@
+^samba3.blackbox.shadow_copy_torture.reading stream of a shadow copy of a file\(fileserver\)
diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index 0e1ffd1101a..888f3bd5154 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -2194,7 +2194,7 @@ sub provision($$$$$$$$$)
[shadow_write]
path = $shadow_tstdir
comment = previous versions snapshots under mount point
- vfs objects = shadow_copy2 error_inject
+ vfs objects = shadow_copy2 streams_xattr error_inject
aio write size = 0
error_inject:pwrite = EBADF
shadow:mountpoint = $shadow_tstdir
diff --git a/source3/script/tests/test_shadow_copy_torture.sh b/source3/script/tests/test_shadow_copy_torture.sh
index d47cd512a20..3b05fc50f72 100755
--- a/source3/script/tests/test_shadow_copy_torture.sh
+++ b/source3/script/tests/test_shadow_copy_torture.sh
@@ -48,6 +48,13 @@ build_snapshots()
build_files $snapdir/$SNAPSHOT
}
+build_stream_on_snapshot()
+{
+ file=$WORKDIR/.snapshots/$SNAPSHOT/foo
+
+ setfattr -n 'user.DosStream.bar:$DATA' -v baz $file || return 1
+}
+
test_shadow_copy_write()
{
local msg
@@ -68,9 +75,40 @@ test_shadow_copy_write()
failed=`expr $failed + 1`
}
+test_shadow_copy_stream()
+{
+ local msg
+
+ msg=$1
+
+ #delete snapshots from previous tests
+ find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1
+ build_snapshots
+ build_stream_on_snapshot || {
+ subunit_start_test msg
+ subunit_skip_test msg <<EOF
+test_shadow_copy_stream needs an fs with xattrs
+EOF
+ return 0
+ }
+
+ testit "reading stream of a shadow copy of a file" \
+ $SMBTORTURE \
+ -U$USERNAME%$PASSWORD \
+ "//$SERVER/shadow_write" \
+ --option="torture:twrp_file=foo" \
+ --option="torture:twrp_stream=bar" \
+ --option="torture:twrp_stream_size=3" \
+ --option="torture:twrp_snapshot=$SNAPSHOT" \
+ smb2.twrp.stream || \
+ failed=`expr $failed + 1`
+}
+
build_files $WORKDIR
# test open for writing and write behaviour of snapshoted files
test_shadow_copy_write "write behaviour of snapshoted files"
+test_shadow_copy_stream "reading stream of snapshotted file"
+
exit $failed
diff --git a/source4/torture/smb2/create.c b/source4/torture/smb2/create.c
index 68447935bd0..912efaac272 100644
--- a/source4/torture/smb2/create.c
+++ b/source4/torture/smb2/create.c
@@ -1809,6 +1809,92 @@ static bool test_twrp_write(struct torture_context *tctx, struct smb2_tree *tree
return ret;
}
+static bool test_twrp_stream(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ struct smb2_create io;
+ NTSTATUS status;
+ bool ret = true;
+ char *p = NULL;
+ struct tm tm;
+ time_t t;
+ uint64_t nttime;
+ const char *file = NULL;
+ const char *stream = NULL;
+ const char *snapshot = NULL;
+ int stream_size;
+ char *path = NULL;
+ uint8_t *buf = NULL;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_read r;
+
+ file = torture_setting_string(tctx, "twrp_file", NULL);
+ if (file == NULL) {
+ torture_skip(tctx, "missing 'twrp_file' option\n");
+ }
+
+ stream = torture_setting_string(tctx, "twrp_stream", NULL);
+ if (stream == NULL) {
+ torture_skip(tctx, "missing 'twrp_stream' option\n");
+ }
+
+ snapshot = torture_setting_string(tctx, "twrp_snapshot", NULL);
+ if (snapshot == NULL) {
+ torture_skip(tctx, "missing 'twrp_snapshot' option\n");
+ }
+
+ stream_size = torture_setting_int(tctx, "twrp_stream_size", 0);
+ if (stream_size == 0) {
+ torture_skip(tctx, "missing 'twrp_stream_size' option\n");
+ }
+
+ torture_comment(tctx, "Testing timewarp on stream (%s) (%s)\n",
+ file, snapshot);
+
+ path = talloc_asprintf(tree, "%s:%s", file, stream);
+ torture_assert_not_null_goto(tctx, path, ret, done, "path\n");
+
+ buf = talloc_zero_array(tree, uint8_t, stream_size);
+ torture_assert_not_null_goto(tctx, buf, ret, done, "buf\n");
+
+ setenv("TZ", "GMT", 1);
+ p = strptime(snapshot, "@GMT-%Y.%m.%d-%H.%M.%S", &tm);
+ torture_assert_goto(tctx, p != NULL, ret, done, "strptime\n");
+ torture_assert_goto(tctx, *p == '\0', ret, done, "strptime\n");
+
+ t = mktime(&tm);
+ unix_to_nt_time(&nttime, t);
+
+ io = (struct smb2_create) {
+ .in.desired_access = SEC_FILE_READ_DATA,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.fname = path,
+ .in.timewarp = nttime,
+ };
+
+ status = smb2_create(tree, tctx, &io);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create\n");
+ h1 = io.out.file.handle;
+
+ r = (struct smb2_read) {
+ .in.file.handle = h1,
+ .in.length = stream_size,
+ .in.offset = 0,
+ };
+
+ status = smb2_read(tree, tree, &r);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create\n");
+
+ smb2_util_close(tree, h1);
+
+done:
+ return ret;
+}
+
/*
basic testing of SMB2 read
*/
@@ -1840,6 +1926,7 @@ struct torture_suite *torture_smb2_twrp_init(TALLOC_CTX *ctx)
struct torture_suite *suite = torture_suite_create(ctx, "twrp");
torture_suite_add_1smb2_test(suite, "write", test_twrp_write);
+ torture_suite_add_1smb2_test(suite, "stream", test_twrp_stream);
suite->description = talloc_strdup(suite, "SMB2-TWRP tests");
--
2.17.2
From 521722199cd810d33416d5d484950c3d796fcf10 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sat, 24 Nov 2018 08:56:49 +0100
Subject: [PATCH 09/13] s3:smbd: prepare filename_convert_internal() for twrp
Bug: https://bugzilla.samba.org/show_bug.cgi?id=13455
Signed-off-by: Ralph Boehme <slow at samba.org>
---
source3/smbd/filename.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 16d0f340102..5b740412cff 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -1591,6 +1591,7 @@ static NTSTATUS filename_convert_internal(TALLOC_CTX *ctx,
bool *ppath_contains_wcard,
struct smb_filename **pp_smb_fname)
{
+ const char *name = NULL;
NTSTATUS status;
*pp_smb_fname = NULL;
@@ -1641,7 +1642,9 @@ static NTSTATUS filename_convert_internal(TALLOC_CTX *ctx,
ucf_flags |= UCF_ALWAYS_ALLOW_WCARD_LCOMP;
}
- status = unix_convert(ctx, conn, name_in, pp_smb_fname, ucf_flags);
+ name = name_in;
+
+ status = unix_convert(ctx, conn, name, pp_smb_fname, ucf_flags);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10,("filename_convert_internal: unix_convert failed "
"for name %s with %s\n",
--
2.17.2
From dad5970de3a17cb9b8c86c9d4d97a619a204cb05 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sat, 24 Nov 2018 09:05:37 +0100
Subject: [PATCH 10/13] s3:smbd: add twrp processing to
filename_convert_internal()
Not used for now, existing callers pass NULL.
Bug: https://bugzilla.samba.org/show_bug.cgi?id=13455
Signed-off-by: Ralph Boehme <slow at samba.org>
---
source3/smbd/filename.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 5b740412cff..a2b9d3ae4e5 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -1575,6 +1575,7 @@ static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
* UCF_ALWAYS_ALLOW_WCARD_LCOMP will be OR'd in if
* p_cont_wcard != NULL and is true and
* UCF_COND_ALLOW_WCARD_LCOMP.
+ * @param twrp Optional VSS time
* @param p_cont_wcard If not NULL, will be set to true if the dfs path
* resolution detects a wildcard.
* @param pp_smb_fname The final converted name will be allocated if the
@@ -1588,10 +1589,12 @@ static NTSTATUS filename_convert_internal(TALLOC_CTX *ctx,
struct smb_request *smbreq,
const char *name_in,
uint32_t ucf_flags,
+ time_t *twrp,
bool *ppath_contains_wcard,
struct smb_filename **pp_smb_fname)
{
const char *name = NULL;
+ char *twrp_name = NULL;
NTSTATUS status;
*pp_smb_fname = NULL;
@@ -1643,6 +1646,25 @@ static NTSTATUS filename_convert_internal(TALLOC_CTX *ctx,
}
name = name_in;
+ if (twrp != NULL) {
+ struct tm *tm = NULL;
+
+ tm = gmtime(twrp);
+ twrp_name = talloc_asprintf(
+ ctx,
+ "@GMT-%04u.%02u.%02u-%02u.%02u.%02u/%s",
+ tm->tm_year + 1900,
+ tm->tm_mon + 1,
+ tm->tm_mday,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec,
+ name);
+ if (twrp_name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ name = twrp_name;
+ }
status = unix_convert(ctx, conn, name, pp_smb_fname, ucf_flags);
if (!NT_STATUS_IS_OK(status)) {
@@ -1650,8 +1672,10 @@ static NTSTATUS filename_convert_internal(TALLOC_CTX *ctx,
"for name %s with %s\n",
name_in,
nt_errstr(status) ));
+ TALLOC_FREE(twrp_name);
return status;
}
+ TALLOC_FREE(twrp_name);
if ((ucf_flags & UCF_UNIX_NAME_LOOKUP) &&
VALID_STAT((*pp_smb_fname)->st) &&
@@ -1694,6 +1718,7 @@ NTSTATUS filename_convert(TALLOC_CTX *ctx,
NULL,
name_in,
ucf_flags,
+ NULL,
ppath_contains_wcard,
pp_smb_fname);
}
@@ -1716,6 +1741,7 @@ NTSTATUS filename_convert_with_privilege(TALLOC_CTX *ctx,
smbreq,
name_in,
ucf_flags,
+ NULL,
ppath_contains_wcard,
pp_smb_fname);
}
--
2.17.2
From 0238551a22473144c98dbb69bd1008d60898f5ad Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sat, 24 Nov 2018 10:45:49 +0100
Subject: [PATCH 11/13] s3:smbd: add twrp args to filename_convert()
All existing callers pass NULL, no change in behaviour.
Bug: https://bugzilla.samba.org/show_bug.cgi?id=13455
Signed-off-by: Ralph Boehme <slow at samba.org>
---
source3/rpc_server/srvsvc/srv_srvsvc_nt.c | 2 ++
source3/smbd/filename.c | 3 ++-
source3/smbd/nttrans.c | 4 ++++
source3/smbd/open.c | 1 +
source3/smbd/proto.h | 1 +
source3/smbd/reply.c | 15 +++++++++++++++
source3/smbd/smb2_create.c | 3 ++-
source3/smbd/smb2_query_directory.c | 1 +
source3/smbd/trans2.c | 8 ++++++++
9 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/source3/rpc_server/srvsvc/srv_srvsvc_nt.c b/source3/rpc_server/srvsvc/srv_srvsvc_nt.c
index ac18a73ef4e..2f318550dec 100644
--- a/source3/rpc_server/srvsvc/srv_srvsvc_nt.c
+++ b/source3/rpc_server/srvsvc/srv_srvsvc_nt.c
@@ -2363,6 +2363,7 @@ WERROR _srvsvc_NetGetFileSecurity(struct pipes_struct *p,
r->in.file,
ucf_flags,
NULL,
+ NULL,
&smb_fname);
if (!NT_STATUS_IS_OK(nt_status)) {
werr = ntstatus_to_werror(nt_status);
@@ -2496,6 +2497,7 @@ WERROR _srvsvc_NetSetFileSecurity(struct pipes_struct *p,
r->in.file,
ucf_flags,
NULL,
+ NULL,
&smb_fname);
if (!NT_STATUS_IS_OK(nt_status)) {
werr = ntstatus_to_werror(nt_status);
diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index a2b9d3ae4e5..d861b51771b 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -1710,6 +1710,7 @@ NTSTATUS filename_convert(TALLOC_CTX *ctx,
connection_struct *conn,
const char *name_in,
uint32_t ucf_flags,
+ time_t *twrp,
bool *ppath_contains_wcard,
struct smb_filename **pp_smb_fname)
{
@@ -1718,7 +1719,7 @@ NTSTATUS filename_convert(TALLOC_CTX *ctx,
NULL,
name_in,
ucf_flags,
- NULL,
+ twrp,
ppath_contains_wcard,
pp_smb_fname);
}
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index 3c9b0ebb3f5..e7991c051c1 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -543,6 +543,7 @@ void reply_ntcreate_and_X(struct smb_request *req)
fname,
ucf_flags,
NULL,
+ NULL,
&smb_fname);
TALLOC_FREE(case_state);
@@ -1115,6 +1116,7 @@ static void call_nt_transact_create(connection_struct *conn,
fname,
ucf_flags,
NULL,
+ NULL,
&smb_fname);
TALLOC_FREE(case_state);
@@ -1636,6 +1638,7 @@ void reply_ntrename(struct smb_request *req)
oldname,
ucf_flags_src,
NULL,
+ NULL,
&smb_fname_old);
if (!NT_STATUS_IS_OK(status)) {
if (NT_STATUS_EQUAL(status,
@@ -1652,6 +1655,7 @@ void reply_ntrename(struct smb_request *req)
status = filename_convert(ctx, conn,
newname,
ucf_flags_dst,
+ NULL,
&dest_has_wcard,
&smb_fname_new);
if (!NT_STATUS_IS_OK(status)) {
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index a323a42609e..40ba319bf3d 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -5570,6 +5570,7 @@ NTSTATUS get_relative_fid_filename(connection_struct *conn,
new_base_name,
ucf_flags,
NULL,
+ NULL,
smb_fname_out);
if (!NT_STATUS_IS_OK(status)) {
goto out;
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index d49cd5c2251..a74a79f7569 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -365,6 +365,7 @@ NTSTATUS filename_convert(TALLOC_CTX *mem_ctx,
connection_struct *conn,
const char *name_in,
uint32_t ucf_flags,
+ time_t *twrp,
bool *ppath_contains_wcard,
struct smb_filename **pp_smb_fname);
NTSTATUS filename_convert_with_privilege(TALLOC_CTX *mem_ctx,
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 49ca1d70411..956b83ae08b 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -1305,6 +1305,7 @@ void reply_checkpath(struct smb_request *req)
name,
ucf_flags,
NULL,
+ NULL,
&smb_fname);
if (!NT_STATUS_IS_OK(status)) {
@@ -1403,6 +1404,7 @@ void reply_getatr(struct smb_request *req)
fname,
ucf_flags,
NULL,
+ NULL,
&smb_fname);
if (!NT_STATUS_IS_OK(status)) {
if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
@@ -1506,6 +1508,7 @@ void reply_setatr(struct smb_request *req)
fname,
ucf_flags,
NULL,
+ NULL,
&smb_fname);
if (!NT_STATUS_IS_OK(status)) {
if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
@@ -1803,6 +1806,7 @@ void reply_search(struct smb_request *req)
nt_status = filename_convert(ctx, conn,
path,
ucf_flags,
+ NULL,
&mask_contains_wcard,
&smb_fname);
if (!NT_STATUS_IS_OK(nt_status)) {
@@ -2146,6 +2150,7 @@ void reply_open(struct smb_request *req)
fname,
ucf_flags,
NULL,
+ NULL,
&smb_fname);
if (!NT_STATUS_IS_OK(status)) {
if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
@@ -2318,6 +2323,7 @@ void reply_open_and_X(struct smb_request *req)
fname,
ucf_flags,
NULL,
+ NULL,
&smb_fname);
if (!NT_STATUS_IS_OK(status)) {
if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
@@ -2562,6 +2568,7 @@ void reply_mknew(struct smb_request *req)
fname,
ucf_flags,
NULL,
+ NULL,
&smb_fname);
if (!NT_STATUS_IS_OK(status)) {
if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
@@ -2698,6 +2705,7 @@ void reply_ctemp(struct smb_request *req)
fname,
ucf_flags,
NULL,
+ NULL,
&smb_fname);
if (!NT_STATUS_IS_OK(status)) {
if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
@@ -3236,6 +3244,7 @@ void reply_unlink(struct smb_request *req)
status = filename_convert(ctx, conn,
name,
ucf_flags,
+ NULL,
&path_contains_wcard,
&smb_fname);
if (!NT_STATUS_IS_OK(status)) {
@@ -6185,6 +6194,7 @@ void reply_mkdir(struct smb_request *req)
directory,
ucf_flags,
NULL,
+ NULL,
&smb_dname);
if (!NT_STATUS_IS_OK(status)) {
if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
@@ -6255,6 +6265,7 @@ void reply_rmdir(struct smb_request *req)
directory,
ucf_flags,
NULL,
+ NULL,
&smb_dname);
if (!NT_STATUS_IS_OK(status)) {
if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
@@ -7377,6 +7388,7 @@ void reply_mv(struct smb_request *req)
conn,
name,
src_ucf_flags,
+ NULL,
&src_has_wcard,
&smb_fname_src);
@@ -7394,6 +7406,7 @@ void reply_mv(struct smb_request *req)
conn,
newname,
dst_ucf_flags,
+ NULL,
&dest_has_wcard,
&smb_fname_dst);
@@ -7687,6 +7700,7 @@ void reply_copy(struct smb_request *req)
status = filename_convert(ctx, conn,
fname_src,
ucf_flags_src,
+ NULL,
&source_has_wild,
&smb_fname_src);
if (!NT_STATUS_IS_OK(status)) {
@@ -7702,6 +7716,7 @@ void reply_copy(struct smb_request *req)
status = filename_convert(ctx, conn,
fname_dst,
ucf_flags_dst,
+ NULL,
&dest_has_wild,
&smb_fname_dst);
if (!NT_STATUS_IS_OK(status)) {
diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index 7f80f6f8138..ac9235c6611 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -423,7 +423,7 @@ static NTSTATUS smbd_smb2_create_durable_lease_check(struct smb_request *smb1req
ucf_flags = filename_create_ucf_flags(smb1req, FILE_OPEN);
status = filename_convert(talloc_tos(), fsp->conn,
filename, ucf_flags,
- NULL, &smb_fname);
+ NULL, NULL, &smb_fname);
TALLOC_FREE(filename);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10, ("filename_convert returned %s\n",
@@ -891,6 +891,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
smb1req->conn,
state->fname,
ucf_flags,
+ NULL,
NULL, /* ppath_contains_wcards */
&smb_fname);
if (!NT_STATUS_IS_OK(status)) {
diff --git a/source3/smbd/smb2_query_directory.c b/source3/smbd/smb2_query_directory.c
index f3b61737da7..fb77edca2bf 100644
--- a/source3/smbd/smb2_query_directory.c
+++ b/source3/smbd/smb2_query_directory.c
@@ -428,6 +428,7 @@ static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx,
conn,
fullpath,
ucf_flags,
+ NULL,
&wcard_has_wild,
&smb_fname);
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 6ec319ce870..306174e597d 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -1296,6 +1296,7 @@ static void call_trans2open(connection_struct *conn,
fname,
ucf_flags,
NULL,
+ NULL,
&smb_fname);
if (!NT_STATUS_IS_OK(status)) {
if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
@@ -2743,6 +2744,7 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da
ntstatus = filename_convert(talloc_tos(), conn,
directory,
ucf_flags,
+ NULL,
&mask_contains_wcard,
&smb_dname);
}
@@ -5857,6 +5859,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
fname,
ucf_flags,
NULL,
+ NULL,
&smb_fname);
if (!NT_STATUS_IS_OK(status)) {
if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
@@ -6695,6 +6698,7 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
oldname,
ucf_flags,
NULL,
+ NULL,
&smb_fname_old);
if (!NT_STATUS_IS_OK(status)) {
return status;
@@ -6770,6 +6774,7 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn,
newname,
ucf_flags,
NULL,
+ NULL,
&smb_fname_dst);
if (!NT_STATUS_IS_OK(status)) {
return status;
@@ -6880,6 +6885,7 @@ static NTSTATUS smb_file_link_information(connection_struct *conn,
newname,
ucf_flags,
NULL,
+ NULL,
&smb_fname_dst);
if (!NT_STATUS_IS_OK(status)) {
return status;
@@ -8828,6 +8834,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
fname,
ucf_flags,
NULL,
+ NULL,
&smb_fname);
if (!NT_STATUS_IS_OK(status)) {
if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
@@ -8977,6 +8984,7 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
directory,
ucf_flags,
NULL,
+ NULL,
&smb_dname);
if (!NT_STATUS_IS_OK(status)) {
--
2.17.2
From e85edb1b344e88bebe38e07159f5e58a033da69d Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sat, 24 Nov 2018 10:54:06 +0100
Subject: [PATCH 12/13] s3:smbd: pass down twrp from SMB2_CREATE to
filename_convert()
Bug: https://bugzilla.samba.org/show_bug.cgi?id=13455
Signed-off-by: Ralph Boehme <slow at samba.org>
---
source3/smbd/smb2_create.c | 29 +++++------------------------
1 file changed, 5 insertions(+), 24 deletions(-)
diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index ac9235c6611..fdd04ac0331 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -476,6 +476,8 @@ struct smbd_smb2_create_state {
ssize_t lease_len;
bool need_replay_cache;
struct smbXsrv_open *op;
+ time_t twrp_time;
+ time_t *twrp_timep;
struct smb2_create_blob *dhnc;
struct smb2_create_blob *dh2c;
@@ -891,7 +893,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
smb1req->conn,
state->fname,
ucf_flags,
- NULL,
+ state->twrp_timep,
NULL, /* ppath_contains_wcards */
&smb_fname);
if (!NT_STATUS_IS_OK(status)) {
@@ -1179,9 +1181,6 @@ static void smbd_smb2_create_before_exec(struct tevent_req *req)
if (state->twrp != NULL) {
NTTIME nttime;
- time_t t;
- struct tm *tm;
- char *tmpname = state->fname;
if (state->twrp->data.length != 8) {
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
@@ -1189,27 +1188,9 @@ static void smbd_smb2_create_before_exec(struct tevent_req *req)
}
nttime = BVAL(state->twrp->data.data, 0);
- t = nt_time_to_unix(nttime);
- tm = gmtime(&t);
+ state->twrp_time = nt_time_to_unix(nttime);
+ state->twrp_timep = &state->twrp_time;
- state->fname = talloc_asprintf(
- state,
- "%s\\@GMT-%04u.%02u.%02u-%02u.%02u.%02u",
- state->fname,
- tm->tm_year + 1900,
- tm->tm_mon + 1,
- tm->tm_mday,
- tm->tm_hour,
- tm->tm_min,
- tm->tm_sec);
- if (tevent_req_nomem(state->fname, req)) {
- return;
- }
- TALLOC_FREE(tmpname);
- /*
- * Tell filename_create_ucf_flags() this
- * is an @GMT path.
- */
smb1req->flags2 |= FLAGS2_REPARSE_PATH;
}
--
2.17.2
From 70cb6d54a0d56c0ebf18a78fb0ab4199ace982c3 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 21 Nov 2018 17:20:30 +0100
Subject: [PATCH 13/13] vfs_shadow_copy2: in fstat also convert fsp->fsp_name
and fsp->base_fsp->fsp_name
Stacked VFS modules might use the file name, not the file
handle. Looking at you, vfs_fruit...
Bug: https://bugzilla.samba.org/show_bug.cgi?id=13455
Signed-off-by: Ralph Boehme <slow at samba.org>
---
selftest/knownfail.d/samba3.blackbox | 1 -
source3/modules/vfs_shadow_copy2.c | 58 ++++++++++++++++++++++++----
2 files changed, 50 insertions(+), 9 deletions(-)
delete mode 100644 selftest/knownfail.d/samba3.blackbox
diff --git a/selftest/knownfail.d/samba3.blackbox b/selftest/knownfail.d/samba3.blackbox
deleted file mode 100644
index a15359e6420..00000000000
--- a/selftest/knownfail.d/samba3.blackbox
+++ /dev/null
@@ -1 +0,0 @@
-^samba3.blackbox.shadow_copy_torture.reading stream of a shadow copy of a file\(fileserver\)
diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c
index e105a813e23..0ddc01737bb 100644
--- a/source3/modules/vfs_shadow_copy2.c
+++ b/source3/modules/vfs_shadow_copy2.c
@@ -1354,21 +1354,63 @@ static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp,
SMB_STRUCT_STAT *sbuf)
{
time_t timestamp = 0;
+ struct smb_filename *orig_smb_fname = NULL;
+ struct smb_filename vss_smb_fname;
+ struct smb_filename *orig_base_smb_fname = NULL;
+ struct smb_filename vss_base_smb_fname;
+ char *stripped = NULL;
+ int saved_errno = 0;
+ bool ok;
int ret;
+ ok = shadow_copy2_strip_snapshot(talloc_tos(), handle,
+ fsp->fsp_name->base_name,
+ ×tamp, &stripped);
+ if (!ok) {
+ return -1;
+ }
+
+ if (timestamp == 0) {
+ TALLOC_FREE(stripped);
+ return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
+ }
+
+ vss_smb_fname = *fsp->fsp_name;
+ vss_smb_fname.base_name = shadow_copy2_convert(talloc_tos(),
+ handle,
+ stripped,
+ timestamp);
+ TALLOC_FREE(stripped);
+ if (vss_smb_fname.base_name == NULL) {
+ return -1;
+ }
+
+ orig_smb_fname = fsp->fsp_name;
+ fsp->fsp_name = &vss_smb_fname;
+
+ if (fsp->base_fsp != NULL) {
+ vss_base_smb_fname = *fsp->base_fsp->fsp_name;
+ vss_base_smb_fname.base_name = vss_smb_fname.base_name;
+ orig_base_smb_fname = fsp->base_fsp->fsp_name;
+ fsp->base_fsp->fsp_name = &vss_base_smb_fname;
+ }
+
ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
- if (ret == -1) {
- return ret;
+ fsp->fsp_name = orig_smb_fname;
+ if (fsp->base_fsp != NULL) {
+ fsp->base_fsp->fsp_name = orig_base_smb_fname;
}
- if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
- fsp->fsp_name->base_name,
- ×tamp, NULL)) {
- return 0;
+ if (ret == -1) {
+ saved_errno = errno;
}
- if (timestamp != 0) {
+
+ if (ret == 0) {
convert_sbuf(handle, fsp->fsp_name->base_name, sbuf);
}
- return 0;
+ if (saved_errno != 0) {
+ errno = saved_errno;
+ }
+ return ret;
}
static int shadow_copy2_open(vfs_handle_struct *handle,
--
2.17.2
More information about the samba-technical
mailing list