[Pkg-samba-maint] [samba] 16/17: Add patches for previous commits
Mathieu Parent
sathieu at moszumanska.debian.org
Thu Mar 30 22:15:34 UTC 2017
This is an automated email from the git hooks/post-receive script.
sathieu pushed a commit to branch jessie
in repository samba.
commit e1ea28f62e42e782b4c85fb24430fd6a4fdb95a4
Author: Mathieu Parent <math.parent at gmail.com>
Date: Thu Mar 30 21:23:34 2017 +0200
Add patches for previous commits
---
debian/patches/bug-12721-4.2.patch | 208 ++++
debian/patches/fix-shadow_copy2-42-backport.patch | 116 ++
debian/patches/series | 3 +
debian/patches/shadow_copy2_tests_42.patch | 1344 +++++++++++++++++++++
4 files changed, 1671 insertions(+)
diff --git a/debian/patches/bug-12721-4.2.patch b/debian/patches/bug-12721-4.2.patch
new file mode 100644
index 0000000..73b9436
--- /dev/null
+++ b/debian/patches/bug-12721-4.2.patch
@@ -0,0 +1,208 @@
+From 5d4ef6ff0970c93fed49e51a01e63cb67d49d087 Mon Sep 17 00:00:00 2001
+From: Jeremy Allison <jra at samba.org>
+Date: Mon, 27 Mar 2017 10:46:47 -0700
+Subject: [PATCH 1/3] s3: smbd: Fix incorrect logic exposed by fix for the
+ security bug 12496 (CVE-2017-2619).
+
+In a UNIX filesystem, the names "." and ".." by definition can *never*
+be symlinks - they are already reserved names.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=12721
+
+Signed-off-by: Jeremy Allison <jra at samba.org>
+Reviewed-by: Uri Simchoni <uri at samba.org>
+(cherry picked from commit ae17bebd250bdde5614b2ac17e53512f19fe9b68)
+---
+ source3/smbd/vfs.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
+index 4d660122f5a..f084b1d1930 100644
+--- a/source3/smbd/vfs.c
++++ b/source3/smbd/vfs.c
+@@ -1291,8 +1291,11 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
+ /* fname can't have changed in resolved_path. */
+ const char *p = &resolved_name[rootdir_len];
+
+- /* *p can be '\0' if fname was "." */
+- if (*p == '\0' && ISDOT(fname)) {
++ /*
++ * UNIX filesystem semantics, names consisting
++ * only of "." or ".." CANNOT be symlinks.
++ */
++ if (ISDOT(fname) || ISDOTDOT(fname)) {
+ goto out;
+ }
+
+--
+2.12.2.564.g063fe858b8-goog
+
+
+From 71500662d1098d17657b0148a0aa06cd69482c7d Mon Sep 17 00:00:00 2001
+From: Jeremy Allison <jra at samba.org>
+Date: Mon, 27 Mar 2017 17:04:58 -0700
+Subject: [PATCH 2/3] s3: smbd: Fix "follow symlink = no" regression part 2.
+
+Add an extra paramter to cwd_name to check_reduced_name().
+
+If cwd_name == NULL then fname is a client given path relative
+to the root path of the share.
+
+If cwd_name != NULL then fname is a client given path relative
+to cwd_name. cwd_name is relative to the root path of the share.
+
+Not yet used, logic added in the next commit.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=12721
+
+Signed-off-by: Jeremy Allison <jra at samba.org>
+Reviewed-by: Ralph Boehme <slow at samba.org>
+(cherry picked from commit 83e30cb48859b412b76572b6a3ba84d8fde167af)
+---
+ source3/smbd/filename.c | 2 +-
+ source3/smbd/open.c | 2 +-
+ source3/smbd/proto.h | 4 +++-
+ source3/smbd/vfs.c | 10 +++++++++-
+ 4 files changed, 14 insertions(+), 4 deletions(-)
+
+diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
+index 3593155ce4e..03773c82403 100644
+--- a/source3/smbd/filename.c
++++ b/source3/smbd/filename.c
+@@ -1222,7 +1222,7 @@ NTSTATUS check_name(connection_struct *conn, const char *name)
+ }
+
+ if (!lp_widelinks(SNUM(conn)) || !lp_follow_symlinks(SNUM(conn))) {
+- status = check_reduced_name(conn,name);
++ status = check_reduced_name(conn, NULL, name);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5,("check_name: name %s failed with %s\n",name,
+ nt_errstr(status)));
+diff --git a/source3/smbd/open.c b/source3/smbd/open.c
+index 84177528511..13aaae3b023 100644
+--- a/source3/smbd/open.c
++++ b/source3/smbd/open.c
+@@ -539,7 +539,7 @@ static int non_widelink_open(struct connection_struct *conn,
+ }
+
+ /* Ensure the relative path is below the share. */
+- status = check_reduced_name(conn, final_component);
++ status = check_reduced_name(conn, parent_dir, final_component);
+ if (!NT_STATUS_IS_OK(status)) {
+ saved_errno = map_errno_from_nt_status(status);
+ goto out;
+diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
+index abfb5435493..032f75de166 100644
+--- a/source3/smbd/proto.h
++++ b/source3/smbd/proto.h
+@@ -1171,7 +1171,9 @@ const char *vfs_readdirname(connection_struct *conn, void *p,
+ SMB_STRUCT_STAT *sbuf, char **talloced);
+ int vfs_ChDir(connection_struct *conn, const char *path);
+ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn);
+-NTSTATUS check_reduced_name(connection_struct *conn, const char *fname);
++NTSTATUS check_reduced_name(connection_struct *conn,
++ const char *cwd_name,
++ const char *fname);
+ NTSTATUS check_reduced_name_with_privilege(connection_struct *conn,
+ const char *fname,
+ struct smb_request *smbreq);
+diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
+index f084b1d1930..15896f80b12 100644
+--- a/source3/smbd/vfs.c
++++ b/source3/smbd/vfs.c
+@@ -1163,9 +1163,17 @@ NTSTATUS check_reduced_name_with_privilege(connection_struct *conn,
+ /*******************************************************************
+ Reduce a file name, removing .. elements and checking that
+ it is below dir in the heirachy. This uses realpath.
++
++ If cwd_name == NULL then fname is a client given path relative
++ to the root path of the share.
++
++ If cwd_name != NULL then fname is a client given path relative
++ to cwd_name. cwd_name is relative to the root path of the share.
+ ********************************************************************/
+
+-NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
++NTSTATUS check_reduced_name(connection_struct *conn,
++ const char *cwd_name,
++ const char *fname)
+ {
+ char *resolved_name = NULL;
+ bool allow_symlinks = true;
+--
+2.12.2.564.g063fe858b8-goog
+
+
+From e3fd46264b82ffc22424ee7364b3fd2c0fc14a7e Mon Sep 17 00:00:00 2001
+From: Jeremy Allison <jra at samba.org>
+Date: Mon, 27 Mar 2017 17:09:38 -0700
+Subject: [PATCH 3/3] s3: smbd: Fix "follow symlink = no" regression part 2.
+
+Use the cwd_name parameter to reconstruct the original
+client name for symlink testing.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=12721
+
+Signed-off-by: Jeremy Allison <jra at samba.org>
+Reviewed-by: Ralph Boehme <slow at samba.org>
+(cherry picked from commit e182a4d39e86c9694e255efdf6ee2ea3ccb9af4a)
+---
+ source3/smbd/vfs.c | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
+index 15896f80b12..6c46fe54364 100644
+--- a/source3/smbd/vfs.c
++++ b/source3/smbd/vfs.c
+@@ -1176,6 +1176,7 @@ NTSTATUS check_reduced_name(connection_struct *conn,
+ const char *fname)
+ {
+ char *resolved_name = NULL;
++ char *new_fname = NULL;
+ bool allow_symlinks = true;
+ bool allow_widelinks = false;
+
+@@ -1317,11 +1318,32 @@ NTSTATUS check_reduced_name(connection_struct *conn,
+ }
+
+ p++;
++
++ /*
++ * If cwd_name is present and not ".",
++ * then fname is relative to that, not
++ * the root of the share. Make sure the
++ * path we check is the one the client
++ * sent (cwd_name+fname).
++ */
++ if (cwd_name != NULL && !ISDOT(cwd_name)) {
++ new_fname = talloc_asprintf(talloc_tos(),
++ "%s/%s",
++ cwd_name,
++ fname);
++ if (new_fname == NULL) {
++ SAFE_FREE(resolved_name);
++ return NT_STATUS_NO_MEMORY;
++ }
++ fname = new_fname;
++ }
++
+ if (strcmp(fname, p)!=0) {
+ DEBUG(2, ("check_reduced_name: Bad access "
+ "attempt: %s is a symlink to %s\n",
+ fname, p));
+ SAFE_FREE(resolved_name);
++ TALLOC_FREE(new_fname);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+@@ -1332,6 +1354,7 @@ NTSTATUS check_reduced_name(connection_struct *conn,
+ DEBUG(3,("check_reduced_name: %s reduced to %s\n", fname,
+ resolved_name));
+ SAFE_FREE(resolved_name);
++ TALLOC_FREE(new_fname);
+ return NT_STATUS_OK;
+ }
+
+--
+2.12.2.564.g063fe858b8-goog
+
diff --git a/debian/patches/fix-shadow_copy2-42-backport.patch b/debian/patches/fix-shadow_copy2-42-backport.patch
new file mode 100644
index 0000000..e87e6c3
--- /dev/null
+++ b/debian/patches/fix-shadow_copy2-42-backport.patch
@@ -0,0 +1,116 @@
+From fddffa9d84e5d3554f64f0935c7140fda785a477 Mon Sep 17 00:00:00 2001
+From: Uri Simchoni <uri at samba.org>
+Date: Wed, 24 Aug 2016 14:42:23 +0300
+Subject: [PATCH 1/2] vfs_shadow_copy: handle non-existant files and wildcards
+
+During path checking, the vfs connectpath_fn is called to
+determine the share's root, relative to the file being
+queried (for example, in snapshot file this may be other
+than the share's "usual" root directory). connectpath_fn
+must be able to answer this question even if the path does
+not exist and its parent does exist. The convention in this
+case is that this refers to a yet-uncreated file under the parent
+and all queries are relative to the parent.
+
+This also serves as a workaround for the case where connectpath_fn
+has to handle wildcards, as with the case of SMB1 trans2 findfirst.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=12172
+
+Signed-off-by: Uri Simchoni <uri at samba.org>
+Reviewed-by: Jeremy Allison <jra at samba.org>
+
+Autobuild-User(master): Jeremy Allison <jra at samba.org>
+Autobuild-Date(master): Thu Aug 25 05:35:29 CEST 2016 on sn-devel-144
+
+(back-ported from commit f41f439335efb352d03a842c370212a0af77262a)
+---
+ source3/modules/vfs_shadow_copy2.c | 31 ++++++++++++++++++++++++++++++-
+ 1 file changed, 30 insertions(+), 1 deletion(-)
+
+diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c
+index c6fffab..2772a7f 100644
+--- a/source3/modules/vfs_shadow_copy2.c
++++ b/source3/modules/vfs_shadow_copy2.c
+@@ -2151,6 +2151,7 @@ static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle,
+ char *tmp = NULL;
+ char *result = NULL;
+ int saved_errno = 0;
++ char *parent_dir = NULL;
+ size_t rootpath_len = 0;
+ struct shadow_copy2_config *config = NULL;
+
+@@ -2176,7 +2177,34 @@ static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle,
+ tmp = shadow_copy2_do_convert(talloc_tos(), handle, stripped, timestamp,
+ &rootpath_len);
+ if (tmp == NULL) {
+- goto done;
++ if (errno != ENOENT) {
++ goto done;
++ }
++
++ /*
++ * If the converted path does not exist, and converting
++ * the parent yields something that does exist, then
++ * this path refers to something that has not been
++ * created yet, relative to the parent path.
++ * The snapshot finding is relative to the parent.
++ * (usually snapshots are read/only but this is not
++ * necessarily true).
++ * This code also covers getting a wildcard in the
++ * last component, because this function is called
++ * prior to sanitizing the path, and in SMB1 we may
++ * get wildcards in path names.
++ */
++ if (!parent_dirname(talloc_tos(), stripped, &parent_dir,
++ NULL)) {
++ errno = ENOMEM;
++ goto done;
++ }
++
++ tmp = shadow_copy2_do_convert(talloc_tos(), handle, parent_dir,
++ timestamp, &rootpath_len);
++ if (tmp == NULL) {
++ goto done;
++ }
+ }
+
+ DEBUG(10,("converted path is [%s] root path is [%.*s]\n", tmp,
+@@ -2203,6 +2231,7 @@ done:
+ }
+ TALLOC_FREE(tmp);
+ TALLOC_FREE(stripped);
++ TALLOC_FREE(parent_dir);
+ if (saved_errno != 0) {
+ errno = saved_errno;
+ }
+--
+2.9.3
+
+
+From 9e8cb52cda24ac82c192a061d7952a63c4a5cc57 Mon Sep 17 00:00:00 2001
+From: Uri Simchoni <uri at samba.org>
+Date: Tue, 28 Mar 2017 08:14:24 +0300
+Subject: [PATCH 2/2] vfs_shadow_copy2: fix crash in 4.2.x backport
+
+Signed-off-by: Uri Simchoni <uri at samba.org>
+---
+ source3/modules/vfs_shadow_copy2.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c
+index 2772a7f..7e38928 100644
+--- a/source3/modules/vfs_shadow_copy2.c
++++ b/source3/modules/vfs_shadow_copy2.c
+@@ -2146,7 +2146,7 @@ static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle,
+ static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle,
+ const char *fname)
+ {
+- time_t timestamp;
++ time_t timestamp = 0;
+ char *stripped = NULL;
+ char *tmp = NULL;
+ char *result = NULL;
+--
+2.9.3
+
diff --git a/debian/patches/series b/debian/patches/series
index 40d925d..3c395b6 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -23,3 +23,6 @@ ctdb-Fix-detection-of-gnukfreebsd.patch
s3-libsmb-Fix-error-where-short-name-length-was-read.patch
security-2016-12-19.patch
CVE-2017-2619.patch
+bug-12721-4.2.patch
+fix-shadow_copy2-42-backport.patch
+shadow_copy2_tests_42.patch
diff --git a/debian/patches/shadow_copy2_tests_42.patch b/debian/patches/shadow_copy2_tests_42.patch
new file mode 100644
index 0000000..f73afa0
--- /dev/null
+++ b/debian/patches/shadow_copy2_tests_42.patch
@@ -0,0 +1,1344 @@
+From 4ef595e10a0530eb397e1ef1607c0c5fec5cc176 Mon Sep 17 00:00:00 2001
+From: Uri Simchoni <uri at samba.org>
+Date: Thu, 29 Oct 2015 22:24:30 +0200
+Subject: [PATCH 01/10] vfs_shadow_copy2: add a blackbox test suite
+
+Add a blackbox test suite for vfs_shadow_copy2, testing
+parameters mountpoint, basedir, snapdir, snapdirseverywhere,
+and testing correct wide-link processing.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=11580
+
+Signed-off-by: Uri Simchoni <uri at samba.org>
+Reviewed-by: Michael Adam <obnox at samba.org>
+
+Autobuild-User(master): Michael Adam <obnox at samba.org>
+Autobuild-Date(master): Wed Jan 13 17:11:38 CET 2016 on sn-devel-144
+
+(back-ported from commit 7362c27a62e3802fc8df975ce50115b683811f4a)
+---
+ selftest/target/Samba3.pm | 80 +++++++++
+ source3/script/tests/test_shadow_copy.sh | 290 +++++++++++++++++++++++++++++++
+ source3/selftest/tests.py | 2 +
+ 3 files changed, 372 insertions(+)
+ create mode 100755 source3/script/tests/test_shadow_copy.sh
+
+diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
+index bb1fd5b..71e3f4e 100755
+--- a/selftest/target/Samba3.pm
++++ b/selftest/target/Samba3.pm
+@@ -893,6 +893,21 @@ sub provision($$$$$$)
+ my $manglenames_shrdir="$shrdir/manglenames";
+ push(@dirs,$manglenames_shrdir);
+
++ my $widelinks_shrdir="$shrdir/widelinks";
++ push(@dirs,$widelinks_shrdir);
++
++ my $widelinks_linkdir="$shrdir/widelinks_foo";
++ push(@dirs,$widelinks_linkdir);
++
++ my $shadow_tstdir="$shrdir/shadow";
++ push(@dirs,$shadow_tstdir);
++ my $shadow_mntdir="$shadow_tstdir/mount";
++ push(@dirs,$shadow_mntdir);
++ my $shadow_basedir="$shadow_mntdir/base";
++ push(@dirs,$shadow_basedir);
++ my $shadow_shrdir="$shadow_basedir/share";
++ push(@dirs,$shadow_shrdir);
++
+ # this gets autocreated by winbindd
+ my $wbsockdir="$prefix_abs/winbindd";
+ my $wbsockprivdir="$lockdir/winbindd_privileged";
+@@ -1121,6 +1136,10 @@ sub provision($$$$$$)
+ # fruit:copyfile is a global option
+ fruit:copyfile = yes
+
++ #this does not mean that we use non-secure test env,
++ #it just means we ALLOW one to be configured.
++ allow insecure wide links = yes
++
+ # Begin extra options
+ $extra_options
+ # End extra options
+@@ -1260,6 +1279,67 @@ sub provision($$$$$$)
+ [dynamic_share]
+ path = $shrdir/%R
+ guest ok = yes
++
++[widelinks_share]
++ path = $widelinks_shrdir
++ wide links = no
++ guest ok = yes
++
++[shadow1]
++ path = $shadow_shrdir
++ comment = previous versions snapshots under mount point
++ vfs objects = shadow_copy2
++ shadow:mountpoint = $shadow_mntdir
++
++[shadow2]
++ path = $shadow_shrdir
++ comment = previous versions snapshots outside mount point
++ vfs objects = shadow_copy2
++ shadow:mountpoint = $shadow_mntdir
++ shadow:snapdir = $shadow_tstdir/.snapshots
++
++[shadow3]
++ path = $shadow_shrdir
++ comment = previous versions with subvolume snapshots, snapshots under base dir
++ vfs objects = shadow_copy2
++ shadow:mountpoint = $shadow_mntdir
++ shadow:basedir = $shadow_basedir
++ shadow:snapdir = $shadow_basedir/.snapshots
++
++[shadow4]
++ path = $shadow_shrdir
++ comment = previous versions with subvolume snapshots, snapshots outside mount point
++ vfs objects = shadow_copy2
++ shadow:mountpoint = $shadow_mntdir
++ shadow:basedir = $shadow_basedir
++ shadow:snapdir = $shadow_tstdir/.snapshots
++
++[shadow5]
++ path = $shadow_shrdir
++ comment = previous versions at volume root snapshots under mount point
++ vfs objects = shadow_copy2
++ shadow:mountpoint = $shadow_shrdir
++
++[shadow6]
++ path = $shadow_shrdir
++ comment = previous versions at volume root snapshots outside mount point
++ vfs objects = shadow_copy2
++ shadow:mountpoint = $shadow_shrdir
++ shadow:snapdir = $shadow_tstdir/.snapshots
++
++[shadow7]
++ path = $shadow_shrdir
++ comment = previous versions snapshots everywhere
++ vfs objects = shadow_copy2
++ shadow:mountpoint = $shadow_mntdir
++ shadow:snapdirseverywhere = yes
++
++[shadow_wl]
++ path = $shadow_shrdir
++ comment = previous versions with wide links allowed
++ vfs objects = shadow_copy2
++ shadow:mountpoint = $shadow_mntdir
++ wide links = yes
+ ";
+ close(CONF);
+
+diff --git a/source3/script/tests/test_shadow_copy.sh b/source3/script/tests/test_shadow_copy.sh
+new file mode 100755
+index 0000000..eecd5b8
+--- /dev/null
++++ b/source3/script/tests/test_shadow_copy.sh
+@@ -0,0 +1,290 @@
++#!/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 SMBCLIENT
++EOF
++exit 1;
++fi
++
++SERVER=${1}
++SERVER_IP=${2}
++DOMAIN=${3}
++USERNAME=${4}
++PASSWORD=${5}
++WORKDIR=${6}
++SMBCLIENT=${7}
++shift 7
++SMBCLIENT="$VALGRIND ${SMBCLIENT}"
++ADDARGS="$*"
++
++incdir=`dirname $0`/../../../testprogs/blackbox
++. $incdir/subunit.sh
++
++SNAPSHOTS[0]='@GMT-2015.10.31-19.40.30'
++SNAPSHOTS[1]='@GMT-2016.10.31-19.40.30'
++SNAPSHOTS[2]='@GMT-2017.10.31-19.40.30'
++SNAPSHOTS[3]='@GMT-2018.10.31-19.40.30'
++SNAPSHOTS[4]='@GMT-2019.10.31-19.40.30'
++SNAPSHOTS[5]='@GMT-2020.10.31-19.40.30'
++SNAPSHOTS[6]='@GMT-2021.10.31-19.40.30'
++SNAPSHOTS[7]='@GMT-2022.10.31-19.40.30'
++SNAPSHOTS[8]='@GMT-2023.10.31-19.40.30'
++SNAPSHOTS[9]='@GMT-2024.10.31-19.40.30'
++
++# build a hierarchy of files, symlinks, and directories
++build_files()
++{
++ local rootdir
++ local prefix
++ local version
++ local destdir
++ rootdir=$1
++ prefix=$2
++ version=$3
++ if [ -n "$prefix" ] ; then
++ destdir=$rootdir/$prefix
++ else
++ destdir=$rootdir
++ fi
++
++ mkdir -p $destdir
++ if [ "$version" = "latest" ] ; then
++ #non-snapshot files
++ # for non-snapshot version, create legit files
++ # so that wide-link checks focus on snapshot files
++ touch $destdir/foo
++ mkdir -p $destdir/bar
++ touch $destdir/bar/baz
++ touch $destdir/bar/lfoo
++ touch $destdir/bar/letcpasswd
++ touch $destdir/bar/loutside
++ elif [ "$version" = "fullsnap" ] ; then
++ #snapshot files
++ touch $destdir/foo
++ mkdir -p $destdir/bar
++ touch $destdir/bar/baz
++ ln -fs ../foo $destdir/bar/lfoo
++ ln -fs /etc/passwd $destdir/bar/letcpasswd
++ ln -fs ../../outside $destdir/bar/loutside
++ touch `dirname $destdir`/outside
++ else #subshare snapshot - at bar
++ touch $destdir/baz
++ ln -fs ../foo $destdir/lfoo
++ ln -fs /etc/passwd $destdir/letcpasswd
++ ln -fs ../../outside $destdir/loutside
++ touch `dirname $destdir`/../outside
++ fi
++
++}
++
++# build a snapshots directory
++build_snapshots()
++{
++ local where #where to build snapshots
++ local prefix #prefix from snapshot dir to share root
++ local start #timestamp index of first snapshot
++ local end #timestamp index of last snapshot
++ local sub #creat a snapshot of subtree of share
++ local snapdir
++ local snapname
++ local i
++ local version
++
++ where=$1
++ prefix=$2
++ start=$3
++ end=$4
++ sub=$5
++
++ snapdir=$where/.snapshots
++ mkdir -p $snapdir
++
++ version="fullsnap"
++ if [ "$sub" = "1" ] ; then
++ version="subsnap"
++ prefix=""
++
++ # a valid link target for an inner symlink -
++ # the link is not broken yet should be blocked
++ # by wide link checks
++ touch $snapdir/foo
++ fi
++
++ for i in `seq $start $end` ; do
++ snapname=${SNAPSHOTS[$i]}
++ mkdir $snapdir/$snapname
++ build_files $snapdir/$snapname "$prefix" $version
++ done
++}
++
++# Test listing previous versions of a file
++test_count_versions()
++{
++ local share
++ local path
++ local expected_count
++ local versions
++
++ share=$1
++ path=$2
++ expected_count=$3
++ versions=`$SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "allinfo $path" | grep "^create_time:" | wc -l`
++ if [ "$versions" = "$expected_count" ] ; then
++ true
++ else
++ echo "expected $expected_count versions of $path, got $versions"
++ false
++ fi
++}
++
++# Test fetching a previous version of a file
++test_fetch_snap_file()
++{
++ local share
++ local path
++ local snapidx
++
++ share=$1
++ path=$2
++ snapidx=$3
++ $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP \
++ -c "get ${SNAPSHOTS[$snapidx]}/$path $WORKDIR/foo"
++}
++
++test_shadow_copy_fixed()
++{
++ local share #share to contact
++ local where #where to place snapshots
++ local prefix #prefix to files inside snapshot
++ local msg
++ local allow_wl
++ local ncopies_allowd
++ local ncopies_blocked
++
++ share=$1
++ where=$2
++ prefix=$3
++ msg=$4
++ allow_wl=$5
++
++ ncopies_allowed=4
++ ncopies_blocked=1
++ if [ -n "$allow_wl" ] ; then
++ ncopies_blocked=4
++ fi
++
++ #delete snapshots from previous tests
++ find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1
++ build_snapshots $WORKDIR/$where "$prefix" 0 2
++
++ testit "$msg - regular file" \
++ test_count_versions $share foo $ncopies_allowed || \
++ failed=`expr $failed + 1`
++
++ testit "$msg - regular file in subdir" \
++ test_count_versions $share bar/baz $ncopies_allowed || \
++ failed=`expr $failed + 1`
++
++ testit "$msg - local symlink" \
++ test_count_versions $share bar/lfoo $ncopies_allowed || \
++ failed=`expr $failed + 1`
++
++ testit "$msg - abs symlink outside" \
++ test_count_versions $share bar/letcpasswd $ncopies_blocked || \
++ failed=`expr $failed + 1`
++
++ testit "$msg - rel symlink outside" \
++ test_count_versions $share bar/loutside $ncopies_blocked || \
++ failed=`expr $failed + 1`
++}
++
++test_shadow_copy_everywhere()
++{
++ local share #share to contact
++
++ share=$1
++
++ #delete snapshots from previous tests
++ find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1
++ build_snapshots "$WORKDIR/mount" "base/share" 0 0
++ build_snapshots "$WORKDIR/mount/base" "share" 1 2
++ build_snapshots "$WORKDIR/mount/base/share" "" 3 5
++ build_snapshots "$WORKDIR/mount/base/share/bar" "" 6 9 1
++
++ testit "snapshots in each dir - regular file" \
++ test_count_versions $share foo 4 || \
++ failed=`expr $failed + 1`
++
++ testit "snapshots in each dir - regular file in subdir" \
++ test_count_versions $share bar/baz 5 || \
++ failed=`expr $failed + 1`
++
++ testit "snapshots in each dir - local symlink (but outside snapshot)" \
++ test_count_versions $share bar/lfoo 1 || \
++ failed=`expr $failed + 1`
++
++ testit "snapshots in each dir - abs symlink outside" \
++ test_count_versions $share bar/letcpasswd 1 || \
++ failed=`expr $failed + 1`
++
++ testit "snapshots in each dir - rel symlink outside" \
++ test_count_versions $share bar/loutside 1 || \
++ failed=`expr $failed + 1`
++
++ #the previous versions of the file bar/lfoo points to are outside its
++ #snapshot, and are not reachable. However, but previous versions
++ #taken at different, non-overlapping times higher up the
++ #hierarchy are still reachable.
++ testit "fetch a previous version of a regular file" \
++ test_fetch_snap_file $share "bar/baz" 6 || \
++ failed=`expr $failed + 1`
++
++ testit_expect_failure "fetch a (non-existent) previous version of a symlink" \
++ test_fetch_snap_file $share "bar/lfoo" 6 || \
++ failed=`expr $failed + 1`
++
++ testit "fetch a previous version of a symlink via browsing (1)" \
++ test_fetch_snap_file $share "bar/lfoo" 0 || \
++ failed=`expr $failed + 1`
++
++ testit "fetch a previous version of a symlink via browsing (2)" \
++ test_fetch_snap_file $share "bar/lfoo" 1 || \
++ failed=`expr $failed + 1`
++
++ testit "fetch a previous version of a symlink via browsing (3)" \
++ test_fetch_snap_file $share "bar/lfoo" 3 || \
++ failed=`expr $failed + 1`
++
++}
++
++#build "latest" files
++build_files $WORKDIR/mount base/share "latest"
++
++failed=0
++
++# a test with wide links allowed - also to verify that what's later
++# being blocked is a result of server security measures and not
++# a testing artifact.
++test_shadow_copy_fixed shadow_wl mount base/share "shadow copies with wide links allowed" 1
++
++# tests for a fixed snapshot location
++test_shadow_copy_fixed shadow1 mount base/share "full volume snapshots mounted under volume"
++test_shadow_copy_fixed shadow2 . base/share "full volume snapshots mounted outside volume"
++test_shadow_copy_fixed shadow3 mount/base share "sub volume snapshots mounted under snapshot point"
++test_shadow_copy_fixed shadow4 . share "sub volume snapshots mounted outside"
++test_shadow_copy_fixed shadow5 mount/base/share "" "full volume snapshots and share mounted under volume"
++test_shadow_copy_fixed shadow6 . "" "full volume snapshots and share mounted outside"
++
++# tests for snapshot everywhere - one snapshot location
++test_shadow_copy_fixed shadow7 mount base/share "'everywhere' full volume snapshots"
++test_shadow_copy_fixed shadow7 mount/base share "'everywhere' sub volume snapshots"
++test_shadow_copy_fixed shadow7 mount/base/share "" "'everywhere' share snapshots"
++
++# a test for snapshots everywhere - multiple snapshot locations
++test_shadow_copy_everywhere shadow7
++
++exit $failed
+diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
+index d27595c..0b236dc 100755
+--- a/source3/selftest/tests.py
++++ b/source3/selftest/tests.py
+@@ -175,6 +175,8 @@ for env in ["s3dc"]:
+ # encrypted
+ plantestsuite("samba3.blackbox.smbclient_s3.crypt (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_smbclient_s3.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$USERID', '$LOCAL_PATH', '$PREFIX', smbclient3, wbinfo, net, configuration, "-e"])
+
++for env in ["simpleserver"]:
++ plantestsuite("samba3.blackbox.shadow_copy2 (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_shadow_copy.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/shadow', smbclient3])
+
+ #
+ # tar command tests
+--
+2.9.3
+
+
+From 61d637b5bd2953dab5b8d158f97ef9e22457b728 Mon Sep 17 00:00:00 2001
+From: Jeremy Allison <jra at samba.org>
+Date: Fri, 19 Aug 2016 16:58:39 -0700
+Subject: [PATCH 02/10] s3: libsmb: Correctly align create contexts in a create
+ call.
+
+SMB2 shadow copy requests are the first time we've used
+create contexts in anger in this codepath. This took me
+longer than I'd like to admit to find :-).
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=12166
+
+Signed-off-by: Jeremy Allison <jra at samba.org>
+Reviewed-by: Uri Simchoni <uri at samba.org>
+(cherry picked from commit f8caadfc78a15fa3aefc9ef6249195767c47aa8f)
+---
+ libcli/smb/smb2cli_create.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/libcli/smb/smb2cli_create.c b/libcli/smb/smb2cli_create.c
+index 0db546c..778b501 100644
+--- a/libcli/smb/smb2cli_create.c
++++ b/libcli/smb/smb2cli_create.c
+@@ -113,6 +113,7 @@ struct tevent_req *smb2cli_create_send(
+ blobs_offset = ((blobs_offset + 3) & ~3);
+
+ if (blob.length > 0) {
++ blobs_offset = ((blobs_offset + 7) & ~7);
+ SIVAL(fixed, 48, blobs_offset + SMB2_HDR_BODY + 56);
+ SIVAL(fixed, 52, blob.length);
+ }
+--
+2.9.3
+
+
+From 6fcfd295946d0d5eddff5bcf6325968173b09477 Mon Sep 17 00:00:00 2001
+From: Jeremy Allison <jra at samba.org>
+Date: Thu, 18 Aug 2016 17:15:01 -0700
+Subject: [PATCH 03/10] s3: libsmb: Add return args to
+ clistr_is_previous_version_path().
+
+Not yet used - we will use these to construct the SMB2 TWrp blob.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=12166
+
+Signed-off-by: Jeremy Allison <jra at samba.org>
+Reviewed-by: Uri Simchoni <uri at samba.org>
+(back-ported from commit 14fd6dca4ef33ee85a2f8578f1ad608d6056da1f)
+---
+ source3/libsmb/clistr.c | 43 +++++++++++++++++++++++++++++++++++++++++++
+ source3/libsmb/proto.h | 4 ++++
+ 2 files changed, 47 insertions(+)
+
+diff --git a/source3/libsmb/clistr.c b/source3/libsmb/clistr.c
+index f1264f6..154b9a1 100644
+--- a/source3/libsmb/clistr.c
++++ b/source3/libsmb/clistr.c
+@@ -37,3 +37,46 @@ size_t clistr_pull_talloc(TALLOC_CTX *ctx,
+ src_len,
+ flags);
+ }
++
++bool clistr_is_previous_version_path(const char *path,
++ const char **startp,
++ const char **endp,
++ time_t *ptime)
++{
++ char *q;
++ time_t timestamp;
++ struct tm tm;
++ const char *p = strstr_m(path, "@GMT-");
++
++ if (p == NULL) {
++ return false;
++ }
++ if (p > path && (p[-1] != '\\')) {
++ return false;
++ }
++ q = strptime(p, GMT_FORMAT, &tm);
++ if (q == NULL) {
++ return false;
++ }
++ tm.tm_isdst = -1;
++ timestamp = timegm(&tm);
++ if (timestamp == (time_t)-1) {
++ return false;
++ }
++ if (q[0] != '\0' && q[0] != '\\') {
++ return false;
++ }
++ if (startp) {
++ *startp = p;
++ }
++ if (endp) {
++ if (q[0] == '\\') {
++ q++;
++ }
++ *endp = q;
++ }
++ if (ptime) {
++ *ptime = timestamp;
++ }
++ return true;
++}
+diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h
+index a4b3c74..db5e874 100644
+--- a/source3/libsmb/proto.h
++++ b/source3/libsmb/proto.h
+@@ -843,6 +843,10 @@ size_t clistr_pull_talloc(TALLOC_CTX *ctx,
+ const void *src,
+ int src_len,
+ int flags);
++bool clistr_is_previous_version_path(const char *path,
++ const char **startp,
++ const char **endp,
++ time_t *ptime);
+
+ /* The following definitions come from libsmb/clitrans.c */
+
+--
+2.9.3
+
+
+From 6140246c5f8c88f259b436f4f4b5e81c02ce2097 Mon Sep 17 00:00:00 2001
+From: Jeremy Allison <jra at samba.org>
+Date: Tue, 16 Aug 2016 15:26:53 -0700
+Subject: [PATCH 04/10] s3: libsmb: Add cli_smb2_shadow_copy_data() function
+ that gets shadow copy info over SMB2.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=12166
+
+Signed-off-by: Jeremy Allison <jra at samba.org>
+Reviewed-by: Uri Simchoni <uri at samba.org>
+(back ported from commit 0c6329bc152fcf08fcef385d2f7ee829485eb1a6)
+---
+ source3/libsmb/cli_smb2_fnum.c | 230 +++++++++++++++++++++++++++++++++++++++++
+ source3/libsmb/cli_smb2_fnum.h | 6 ++
+ 2 files changed, 236 insertions(+)
+
+diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
+index 95153ec..15eaf96 100644
+--- a/source3/libsmb/cli_smb2_fnum.c
++++ b/source3/libsmb/cli_smb2_fnum.c
+@@ -38,6 +38,8 @@
+ #include "lib/util/tevent_ntstatus.h"
+ #include "../libcli/security/security.h"
+ #include "lib/util_ea.h"
++#include "librpc/gen_ndr/ndr_ioctl.h"
++#include "ntioctl.h"
+
+ struct smb2_hnd {
+ uint64_t fid_persistent;
+@@ -2578,3 +2580,231 @@ NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
+ }
+ return NT_STATUS_OK;
+ }
++
++/***************************************************************
++ SMB2 enum shadow copy data.
++***************************************************************/
++
++struct cli_smb2_shadow_copy_data_fnum_state {
++ struct cli_state *cli;
++ uint16_t fnum;
++ struct smb2_hnd *ph;
++ DATA_BLOB out_input_buffer;
++ DATA_BLOB out_output_buffer;
++};
++
++static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
++
++static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
++ TALLOC_CTX *mem_ctx,
++ struct tevent_context *ev,
++ struct cli_state *cli,
++ uint16_t fnum,
++ bool get_names)
++{
++ struct tevent_req *req, *subreq;
++ struct cli_smb2_close_fnum_state *state;
++ NTSTATUS status;
++
++ req = tevent_req_create(mem_ctx, &state,
++ struct cli_smb2_shadow_copy_data_fnum_state);
++ if (req == NULL) {
++ return NULL;
++ }
++
++ if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
++ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
++ return tevent_req_post(req, ev);
++ }
++
++ state->cli = cli;
++ state->fnum = fnum;
++
++ status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
++ if (tevent_req_nterror(req, status)) {
++ return tevent_req_post(req, ev);
++ }
++
++ /*
++ * TODO. Under SMB2 we should send a zero max_output_length
++ * ioctl to get the required size, then send another ioctl
++ * to get the data, but the current SMB1 implementation just
++ * does one roundtrip with a 64K buffer size. Do the same
++ * for now. JRA.
++ */
++
++ subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
++ state->cli->timeout,
++ state->cli->smb2.session,
++ state->cli->smb2.tcon,
++ state->ph->fid_persistent, /* in_fid_persistent */
++ state->ph->fid_volatile, /* in_fid_volatile */
++ FSCTL_GET_SHADOW_COPY_DATA,
++ 0, /* in_max_input_length */
++ NULL, /* in_input_buffer */
++ get_names ?
++ CLI_BUFFER_SIZE : 16, /* in_max_output_length */
++ NULL, /* in_output_buffer */
++ SMB2_IOCTL_FLAG_IS_FSCTL);
++
++ if (tevent_req_nomem(subreq, req)) {
++ return tevent_req_post(req, ev);
++ }
++ tevent_req_set_callback(subreq,
++ cli_smb2_shadow_copy_data_fnum_done,
++ req);
++
++ return req;
++}
++
++static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
++{
++ struct tevent_req *req = tevent_req_callback_data(
++ subreq, struct tevent_req);
++ struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
++ req, struct cli_smb2_shadow_copy_data_fnum_state);
++ NTSTATUS status;
++
++ status = smb2cli_ioctl_recv(subreq, state,
++ &state->out_input_buffer,
++ &state->out_output_buffer);
++ TALLOC_FREE(subreq);
++ if (tevent_req_nterror(req, status)) {
++ return;
++ }
++ tevent_req_done(req);
++}
++
++static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
++ TALLOC_CTX *mem_ctx,
++ bool get_names,
++ char ***pnames,
++ int *pnum_names)
++{
++ struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
++ req, struct cli_smb2_shadow_copy_data_fnum_state);
++ char **names = NULL;
++ uint32_t num_names = 0;
++ uint32_t num_names_returned = 0;
++ uint32_t dlength = 0;
++ uint32_t i;
++ uint8_t *endp = NULL;
++ NTSTATUS status;
++
++ if (tevent_req_is_nterror(req, &status)) {
++ return status;
++ }
++
++ if (state->out_output_buffer.length < 16) {
++ return NT_STATUS_INVALID_NETWORK_RESPONSE;
++ }
++
++ num_names = IVAL(state->out_output_buffer.data, 0);
++ num_names_returned = IVAL(state->out_output_buffer.data, 4);
++ dlength = IVAL(state->out_output_buffer.data, 8);
++
++ if (num_names > 0x7FFFFFFF) {
++ return NT_STATUS_INVALID_NETWORK_RESPONSE;
++ }
++
++ if (get_names == false) {
++ *pnum_names = (int)num_names;
++ return NT_STATUS_OK;
++ }
++ if (num_names != num_names_returned) {
++ return NT_STATUS_INVALID_NETWORK_RESPONSE;
++ }
++ if (dlength + 12 < 12) {
++ return NT_STATUS_INVALID_NETWORK_RESPONSE;
++ }
++ /*
++ * NB. The below is an allowable return if there are
++ * more snapshots than the buffer size we told the
++ * server we can receive. We currently don't support
++ * this.
++ */
++ if (dlength + 12 > state->out_output_buffer.length) {
++ return NT_STATUS_INVALID_NETWORK_RESPONSE;
++ }
++ if (state->out_output_buffer.length +
++ (2 * sizeof(SHADOW_COPY_LABEL)) <
++ state->out_output_buffer.length) {
++ return NT_STATUS_INVALID_NETWORK_RESPONSE;
++ }
++
++ names = talloc_array(mem_ctx, char *, num_names_returned);
++ if (names == NULL) {
++ return NT_STATUS_NO_MEMORY;
++ }
++
++ endp = state->out_output_buffer.data +
++ state->out_output_buffer.length;
++
++ for (i=0; i<num_names_returned; i++) {
++ bool ret;
++ uint8_t *src;
++ size_t converted_size;
++
++ src = state->out_output_buffer.data + 12 +
++ (i * 2 * sizeof(SHADOW_COPY_LABEL));
++
++ if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
++ return NT_STATUS_INVALID_NETWORK_RESPONSE;
++ }
++ ret = convert_string_talloc(
++ names, CH_UTF16LE, CH_UNIX,
++ src, 2 * sizeof(SHADOW_COPY_LABEL),
++ &names[i], &converted_size);
++ if (!ret) {
++ TALLOC_FREE(names);
++ return NT_STATUS_INVALID_NETWORK_RESPONSE;
++ }
++ }
++ *pnum_names = num_names;
++ *pnames = names;
++ return NT_STATUS_OK;
++}
++
++NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
++ struct cli_state *cli,
++ uint16_t fnum,
++ bool get_names,
++ char ***pnames,
++ int *pnum_names)
++{
++ TALLOC_CTX *frame = talloc_stackframe();
++ struct tevent_context *ev;
++ struct tevent_req *req;
++ NTSTATUS status = NT_STATUS_NO_MEMORY;
++
++ 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;
++ }
++ ev = samba_tevent_context_init(frame);
++ if (ev == NULL) {
++ goto fail;
++ }
++ req = cli_smb2_shadow_copy_data_fnum_send(frame,
++ ev,
++ cli,
++ fnum,
++ get_names);
++ if (req == NULL) {
++ goto fail;
++ }
++ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
++ goto fail;
++ }
++ status = cli_smb2_shadow_copy_data_fnum_recv(req,
++ mem_ctx,
++ get_names,
++ pnames,
++ pnum_names);
++ fail:
++ TALLOC_FREE(frame);
++ return status;
++}
+diff --git a/source3/libsmb/cli_smb2_fnum.h b/source3/libsmb/cli_smb2_fnum.h
+index 173dba0..cc88bba 100644
+--- a/source3/libsmb/cli_smb2_fnum.h
++++ b/source3/libsmb/cli_smb2_fnum.h
+@@ -176,4 +176,10 @@ struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
+ size_t size);
+ NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
+ size_t *pwritten);
++NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
++ struct cli_state *cli,
++ uint16_t fnum,
++ bool get_names,
++ char ***pnames,
++ int *pnum_names);
+ #endif /* __SMB2CLI_FNUM_H__ */
+--
+2.9.3
+
+
+From bde0de6a381147a55ffcafda98b31005e8f3b2a3 Mon Sep 17 00:00:00 2001
+From: Jeremy Allison <jra at samba.org>
+Date: Tue, 16 Aug 2016 15:27:55 -0700
+Subject: [PATCH 05/10] s3: libsmb: Plumb new SMB2 shadow copy call into
+ cli_shadow_copy_data().
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=12166
+
+Signed-off-by: Jeremy Allison <jra at samba.org>
+Reviewed-by: Uri Simchoni <uri at samba.org>
+(cherry picked from commit 03bf1f858d1c474f9522cb0f5b264c4f6c2ca5b9)
+---
+ source3/libsmb/clifile.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c
+index e4480c6..c5f56f9 100644
+--- a/source3/libsmb/clifile.c
++++ b/source3/libsmb/clifile.c
+@@ -6019,11 +6019,22 @@ NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
+ uint16_t fnum, bool get_names,
+ char ***pnames, int *pnum_names)
+ {
+- TALLOC_CTX *frame = talloc_stackframe();
++ TALLOC_CTX *frame = NULL;
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
++ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
++ return cli_smb2_shadow_copy_data(mem_ctx,
++ cli,
++ fnum,
++ get_names,
++ pnames,
++ pnum_names);
++ }
++
++ frame = talloc_stackframe();
++
+ if (smbXcli_conn_has_async_calls(cli->conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+--
+2.9.3
+
+
+From 4411067b09babe1f7305616a63b7df54c2737611 Mon Sep 17 00:00:00 2001
+From: Jeremy Allison <jra at samba.org>
+Date: Fri, 19 Aug 2016 17:00:25 -0700
+Subject: [PATCH 06/10] s3: libsmb: Add the capability to find a @GMT- path in
+ an SMB2 create and transform to a timewarp token.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=12166
+
+Signed-off-by: Jeremy Allison <jra at samba.org>
+Reviewed-by: Uri Simchoni <uri at samba.org>
+
+Autobuild-User(master): Jeremy Allison <jra at samba.org>
+Autobuild-Date(master): Mon Aug 22 22:59:22 CEST 2016 on sn-devel-144
+
+(back ported from commit 272f5c95cfb3d8035939dada7bd473058c7b6517)
+---
+ source3/libsmb/cli_smb2_fnum.c | 55 +++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 54 insertions(+), 1 deletion(-)
+
+diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
+index 15eaf96..53a6e0f 100644
+--- a/source3/libsmb/cli_smb2_fnum.c
++++ b/source3/libsmb/cli_smb2_fnum.c
+@@ -177,6 +177,11 @@ struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx,
+ {
+ struct tevent_req *req, *subreq;
+ struct cli_smb2_create_fnum_state *state;
++ size_t fname_len = 0;
++ const char *startp = NULL;
++ const char *endp = NULL;
++ time_t tstamp = (time_t)0;
++ struct smb2_create_blobs *cblobs = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_smb2_create_fnum_state);
+@@ -194,10 +199,58 @@ struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx,
+ create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
+ }
+
++ /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
++ fname_len = strlen(fname);
++ if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) {
++ size_t len_before_gmt = startp - fname;
++ size_t len_after_gmt = fname + fname_len - endp;
++ DATA_BLOB twrp_blob;
++ NTTIME ntt;
++ NTSTATUS status;
++
++ char *new_fname = talloc_array(state, char,
++ len_before_gmt + len_after_gmt + 1);
++
++ if (tevent_req_nomem(new_fname, req)) {
++ return tevent_req_post(req, ev);
++ }
++
++ memcpy(new_fname, fname, len_before_gmt);
++ memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
++ fname = new_fname;
++ fname_len = len_before_gmt + len_after_gmt;
++
++ unix_to_nt_time(&ntt, tstamp);
++ twrp_blob = data_blob_const((const void *)&ntt, 8);
++
++ cblobs = talloc_zero(state, struct smb2_create_blobs);
++ if (tevent_req_nomem(cblobs, req)) {
++ return tevent_req_post(req, ev);
++ }
++
++ status = smb2_create_blob_add(state, cblobs,
++ SMB2_CREATE_TAG_TWRP, twrp_blob);
++ if (!NT_STATUS_IS_OK(status)) {
++ tevent_req_nterror(req, status);
++ return tevent_req_post(req, ev);
++ }
++ }
++
+ /* SMB2 is pickier about pathnames. Ensure it doesn't
+ start in a '\' */
+ if (*fname == '\\') {
+ fname++;
++ fname_len--;
++ }
++
++ /* Or end in a '\' */
++ if (fname_len > 0 && fname[fname_len-1] == '\\') {
++ char *new_fname = talloc_strdup(state, fname);
++ if (tevent_req_nomem(new_fname, req)) {
++ return tevent_req_post(req, ev);
++ }
++ new_fname[fname_len-1] = '\0';
++ fname = new_fname;
+ }
+
+ subreq = smb2cli_create_send(state, ev,
+@@ -213,7 +266,7 @@ struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx,
+ share_access,
+ create_disposition,
+ create_options,
+- NULL);
++ cblobs);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+--
+2.9.3
+
+
+From 55682a41a6acc23abba0fa90ad70e2b7797e657a Mon Sep 17 00:00:00 2001
+From: Uri Simchoni <uri at samba.org>
+Date: Tue, 16 Aug 2016 07:19:04 +0300
+Subject: [PATCH 07/10] s2-selftest: run shadow_copy2 test both in NT1 and SMB3
+ modes
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=12172
+
+Signed-off-by: Uri Simchoni <uri at samba.org>
+Reviewed-by: Jeremy Allison <jra at samba.org>
+(back ported from commit c695faa7f94feb8c0a02a9e2f0472af20047bf65)
+---
+ source3/script/tests/test_shadow_copy.sh | 4 ++--
+ source3/selftest/tests.py | 3 ++-
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/source3/script/tests/test_shadow_copy.sh b/source3/script/tests/test_shadow_copy.sh
+index eecd5b8..6ac76b0 100755
+--- a/source3/script/tests/test_shadow_copy.sh
++++ b/source3/script/tests/test_shadow_copy.sh
+@@ -5,7 +5,7 @@
+
+ if [ $# -lt 7 ]; then
+ cat <<EOF
+-Usage: test_shadow_copy SERVER SERVER_IP DOMAIN USERNAME PASSWORD WORKDIR SMBCLIENT
++Usage: test_shadow_copy SERVER SERVER_IP DOMAIN USERNAME PASSWORD WORKDIR SMBCLIENT PARAMS
+ EOF
+ exit 1;
+ fi
+@@ -18,8 +18,8 @@ PASSWORD=${5}
+ WORKDIR=${6}
+ SMBCLIENT=${7}
+ shift 7
+-SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+ ADDARGS="$*"
++SMBCLIENT="$VALGRIND ${SMBCLIENT} ${ADDARGS}"
+
+ incdir=`dirname $0`/../../../testprogs/blackbox
+ . $incdir/subunit.sh
+diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
+index 0b236dc..d24b540 100755
+--- a/source3/selftest/tests.py
++++ b/source3/selftest/tests.py
+@@ -176,7 +176,8 @@ for env in ["s3dc"]:
+ plantestsuite("samba3.blackbox.smbclient_s3.crypt (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_smbclient_s3.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$USERID', '$LOCAL_PATH', '$PREFIX', smbclient3, wbinfo, net, configuration, "-e"])
+
+ for env in ["simpleserver"]:
+- plantestsuite("samba3.blackbox.shadow_copy2 (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_shadow_copy.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/shadow', 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'])
+
+ #
+ # tar command tests
+--
+2.9.3
+
+
+From c7247e7f68e2ac4d54d0bae0322cd5b6e7264dbe Mon Sep 17 00:00:00 2001
+From: Uri Simchoni <uri at samba.org>
+Date: Tue, 23 Aug 2016 11:33:52 +0300
+Subject: [PATCH 08/10] selftest: add content to files created during
+ shadow_copy2 test
+
+This will allow reading them and verifying we got the right version
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=12172
+
+Signed-off-by: Uri Simchoni <uri at samba.org>
+Reviewed-by: Jeremy Allison <jra at samba.org>
+(cherry picked from commit 523046080dd65607eacb901d58ee3b6e54de865e)
+---
+ source3/script/tests/test_shadow_copy.sh | 26 ++++++++++++++------------
+ 1 file changed, 14 insertions(+), 12 deletions(-)
+
+diff --git a/source3/script/tests/test_shadow_copy.sh b/source3/script/tests/test_shadow_copy.sh
+index 6ac76b0..21dcfd6 100755
+--- a/source3/script/tests/test_shadow_copy.sh
++++ b/source3/script/tests/test_shadow_copy.sh
+@@ -42,9 +42,11 @@ build_files()
+ local prefix
+ local version
+ local destdir
++ local content
+ rootdir=$1
+ prefix=$2
+ version=$3
++ content=$4
+ if [ -n "$prefix" ] ; then
+ destdir=$rootdir/$prefix
+ else
+@@ -56,27 +58,27 @@ build_files()
+ #non-snapshot files
+ # for non-snapshot version, create legit files
+ # so that wide-link checks focus on snapshot files
+- touch $destdir/foo
++ echo "$content" > $destdir/foo
+ mkdir -p $destdir/bar
+- touch $destdir/bar/baz
+- touch $destdir/bar/lfoo
+- touch $destdir/bar/letcpasswd
+- touch $destdir/bar/loutside
++ echo "$content" > $destdir/bar/baz
++ echo "$content" > $destdir/bar/lfoo
++ echo "$content" > $destdir/bar/letcpasswd
++ echo "$content" > $destdir/bar/loutside
+ elif [ "$version" = "fullsnap" ] ; then
+ #snapshot files
+- touch $destdir/foo
++ echo "$content" > $destdir/foo
+ mkdir -p $destdir/bar
+- touch $destdir/bar/baz
++ echo "$content" > $destdir/bar/baz
+ ln -fs ../foo $destdir/bar/lfoo
+ ln -fs /etc/passwd $destdir/bar/letcpasswd
+ ln -fs ../../outside $destdir/bar/loutside
+- touch `dirname $destdir`/outside
++ echo "$content" > `dirname $destdir`/outside
+ else #subshare snapshot - at bar
+- touch $destdir/baz
++ echo "$content" > $destdir/baz
+ ln -fs ../foo $destdir/lfoo
+ ln -fs /etc/passwd $destdir/letcpasswd
+ ln -fs ../../outside $destdir/loutside
+- touch `dirname $destdir`/../outside
++ echo "$content" > `dirname $destdir`/../outside
+ fi
+
+ }
+@@ -117,7 +119,7 @@ build_snapshots()
+ for i in `seq $start $end` ; do
+ snapname=${SNAPSHOTS[$i]}
+ mkdir $snapdir/$snapname
+- build_files $snapdir/$snapname "$prefix" $version
++ build_files $snapdir/$snapname "$prefix" $version "$snapname"
+ done
+ }
+
+@@ -262,7 +264,7 @@ test_shadow_copy_everywhere()
+ }
+
+ #build "latest" files
+-build_files $WORKDIR/mount base/share "latest"
++build_files $WORKDIR/mount base/share "latest" "latest"
+
+ failed=0
+
+--
+2.9.3
+
+
+From 72764606cf0560ebbb47f536f14ef86459f94ac1 Mon Sep 17 00:00:00 2001
+From: Uri Simchoni <uri at samba.org>
+Date: Tue, 23 Aug 2016 14:03:30 +0300
+Subject: [PATCH 09/10] selftest: check file readability in shadow_copy2 test
+
+Add tests which verify that a snapshot file is readable
+if and only if it its metadata can be retrieved. Also
+verify (in most tests) that file is retrieved from the
+correct snapshot.
+
+Together with the existing test for number of previous
+versions we can stat, this test checks that we can read
+those files, and also that we cannot break out of a snapshot
+if wide links are not allowed.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=12172
+
+Signed-off-by: Uri Simchoni <uri at samba.org>
+Reviewed-by: Jeremy Allison <jra at samba.org>
+(backported from commit 495b8177363bf1930f3afb373ad73caac022f353)
+---
+ source3/script/tests/test_shadow_copy.sh | 42 +++++++++++++++++++++++++++-----
+ 1 file changed, 36 insertions(+), 6 deletions(-)
+
+diff --git a/source3/script/tests/test_shadow_copy.sh b/source3/script/tests/test_shadow_copy.sh
+index 21dcfd6..7ef1060 100755
+--- a/source3/script/tests/test_shadow_copy.sh
++++ b/source3/script/tests/test_shadow_copy.sh
+@@ -129,18 +129,48 @@ test_count_versions()
+ local share
+ local path
+ local expected_count
++ local skip_content
+ local versions
++ local tstamps
++ local tstamp
++ local content
+
+ share=$1
+ path=$2
+ expected_count=$3
++ skip_content=$4
+ versions=`$SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "allinfo $path" | grep "^create_time:" | wc -l`
+- if [ "$versions" = "$expected_count" ] ; then
+- true
+- else
++ if [ "$versions" != "$expected_count" ] ; then
+ echo "expected $expected_count versions of $path, got $versions"
+- false
++ return 1
+ fi
++
++ #readable snapshots
++ tstamps=`$SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "allinfo $path" | awk '/^@GMT-/ {snapshot=$1} /^create_time:/ {printf "%s\n", snapshot}'`
++ for tstamp in $tstamps ; do
++ if ! $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "get $tstamp\\$path $WORKDIR/foo" ; then
++ echo "Failed getting \\\\$SERVER\\$share\\$tstamp\\$path"
++ return 1
++ fi
++ #also check the content, but not for wide links
++ if [ "x$skip_content" != "x1" ] ; then
++ content=`cat $WORKDIR/foo`
++ if [ "$content" != "$tstamp" ] ; then
++ echo "incorrect content of \\\\$SERVER\\$share\\$tstamp\\$path expected [$tstamp] got [$content]"
++ return 1
++ fi
++ fi
++ done
++
++ #non-readable snapshots
++ tstamps=`$SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "allinfo $path" | \
++ awk '/^@GMT-/ {if (snapshot!=""){printf "%s\n", snapshot} ; snapshot=$1} /^create_time:/ {snapshot=""} END {if (snapshot!=""){printf "%s\n", snapshot}}'`
++ for tstamp in $tstamps ; do
++ if $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "get $tstamp\\$path $WORKDIR/foo" ; then
++ echo "Unexpected success getting \\\\$SERVER\\$share\\$tstamp\\$path"
++ return 1
++ fi
++ done
+ }
+
+ # Test fetching a previous version of a file
+@@ -196,11 +226,11 @@ test_shadow_copy_fixed()
+ failed=`expr $failed + 1`
+
+ testit "$msg - abs symlink outside" \
+- test_count_versions $share bar/letcpasswd $ncopies_blocked || \
++ test_count_versions $share bar/letcpasswd $ncopies_blocked 1 || \
+ failed=`expr $failed + 1`
+
+ testit "$msg - rel symlink outside" \
+- test_count_versions $share bar/loutside $ncopies_blocked || \
++ test_count_versions $share bar/loutside $ncopies_blocked 1 || \
+ failed=`expr $failed + 1`
+ }
+
+--
+2.9.3
+
+
+From 747c519ee59f386f905b33e4ce78ddf3521f8194 Mon Sep 17 00:00:00 2001
+From: Uri Simchoni <uri at samba.org>
+Date: Tue, 23 Aug 2016 14:29:39 +0300
+Subject: [PATCH 10/10] selftest: test listing directories inside snapshots
+
+Verify that directories are also listable.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=12172
+
+Signed-off-by: Uri Simchoni <uri at samba.org>
+Reviewed-by: Jeremy Allison <jra at samba.org>
+(back ported from commit 22c3982100a1d6bf67979a0659604942ef6f11f0)
+---
+ source3/script/tests/test_shadow_copy.sh | 40 +++++++++++++++++++++++++++-----
+ 1 file changed, 34 insertions(+), 6 deletions(-)
+
+diff --git a/source3/script/tests/test_shadow_copy.sh b/source3/script/tests/test_shadow_copy.sh
+index 7ef1060..dfc22ec 100755
+--- a/source3/script/tests/test_shadow_copy.sh
++++ b/source3/script/tests/test_shadow_copy.sh
+@@ -134,6 +134,7 @@ test_count_versions()
+ local tstamps
+ local tstamp
+ local content
++ local is_dir
+
+ share=$1
+ path=$2
+@@ -145,13 +146,28 @@ test_count_versions()
+ return 1
+ fi
+
++ is_dir=0
++ $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "allinfo $path" | grep "^attributes:.*D" && is_dir=1
++ if [ $is_dir = 1 ] ; then
++ skip_content=1
++ fi
++
+ #readable snapshots
+ tstamps=`$SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "allinfo $path" | awk '/^@GMT-/ {snapshot=$1} /^create_time:/ {printf "%s\n", snapshot}'`
+ for tstamp in $tstamps ; do
+- if ! $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "get $tstamp\\$path $WORKDIR/foo" ; then
+- echo "Failed getting \\\\$SERVER\\$share\\$tstamp\\$path"
+- return 1
++ if [ $is_dir = 0 ] ;
++ then
++ if ! $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "get $tstamp\\$path $WORKDIR/foo" ; then
++ echo "Failed getting \\\\$SERVER\\$share\\$tstamp\\$path"
++ return 1
++ fi
++ else
++ if ! $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "ls $tstamp\\$path\\*" ; then
++ echo "Failed listing \\\\$SERVER\\$share\\$tstamp\\$path"
++ return 1
++ fi
+ fi
++
+ #also check the content, but not for wide links
+ if [ "x$skip_content" != "x1" ] ; then
+ content=`cat $WORKDIR/foo`
+@@ -166,9 +182,17 @@ test_count_versions()
+ tstamps=`$SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "allinfo $path" | \
+ awk '/^@GMT-/ {if (snapshot!=""){printf "%s\n", snapshot} ; snapshot=$1} /^create_time:/ {snapshot=""} END {if (snapshot!=""){printf "%s\n", snapshot}}'`
+ for tstamp in $tstamps ; do
+- if $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "get $tstamp\\$path $WORKDIR/foo" ; then
+- echo "Unexpected success getting \\\\$SERVER\\$share\\$tstamp\\$path"
+- return 1
++ if [ $is_dir = 0 ] ;
++ then
++ if $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "get $tstamp\\$path $WORKDIR/foo" ; then
++ echo "Unexpected success getting \\\\$SERVER\\$share\\$tstamp\\$path"
++ return 1
++ fi
++ else
++ if $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "ls $tstamp\\$path\\*" ; then
++ echo "Unexpected success listing \\\\$SERVER\\$share\\$tstamp\\$path"
++ return 1
++ fi
+ fi
+ done
+ }
+@@ -232,6 +256,10 @@ test_shadow_copy_fixed()
+ testit "$msg - rel symlink outside" \
+ test_count_versions $share bar/loutside $ncopies_blocked 1 || \
+ failed=`expr $failed + 1`
++
++ testit "$msg - list directory" \
++ test_count_versions $share bar $ncopies_allowed || \
++ failed=`expr $failed + 1`
+ }
+
+ test_shadow_copy_everywhere()
+--
+2.9.3
+
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-samba/samba.git
More information about the Pkg-samba-maint
mailing list