Subject: [PATCH 20/20] s3: VFS: Don't allow symlink, link or rename on already converted paths.

From: Jeremy Allison <[email-masked]>
Date: Thu, 26 Jan 2017 17:19:24 -0800

Snapshot paths are a read-only filesystem.

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

Signed-off-by: Jeremy Allison <[email-masked]>
Reviewed-by: Uri Simchoni <[email-masked]>

Autobuild-User(master): Jeremy Allison <[email-masked]>
Autobuild-Date(master): Mon Jan 30 22:26:29 CET 2017 on sn-devel-144

(backported from commit 0e1deb77f2b310ad7e5dd784174207adacf1c981)
---
 source3/modules/vfs_shadow_copy2.c | 55 +++++++++++++++++++++++++++++---------
 1 file changed, 43 insertions(+), 12 deletions(-)

diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c
index f773d4f..1345ca2 100644
--- a/source3/modules/vfs_shadow_copy2.c
+++ b/source3/modules/vfs_shadow_copy2.c
@@ -903,15 +903,17 @@ static int shadow_copy2_rename(vfs_handle_struct *handle,
 {
 	time_t timestamp_src = 0;
 	time_t timestamp_dst = 0;
+	char *snappath_src = NULL;
+	char *snappath_dst = NULL;
 
-	if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
+	if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle,
 					 smb_fname_src->base_name,
-					 &timestamp_src, NULL)) {
+					 &timestamp_src, NULL, &snappath_src)) {
 		return -1;
 	}
-	if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
+	if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle,
 					 smb_fname_dst->base_name,
-					 &timestamp_dst, NULL)) {
+					 &timestamp_dst, NULL, &snappath_dst)) {
 		return -1;
 	}
 	if (timestamp_src != 0) {
@@ -922,6 +924,17 @@ static int shadow_copy2_rename(vfs_handle_struct *handle,
 		errno = EROFS;
 		return -1;
 	}
+	/*
+	 * Don't allow rename on already converted paths.
+	 */
+	if (snappath_src != NULL) {
+		errno = EXDEV;
+		return -1;
+	}
+	if (snappath_dst != NULL) {
+		errno = EROFS;
+		return -1;
+	}
 	return SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
 }
 
@@ -930,19 +943,28 @@ static int shadow_copy2_symlink(vfs_handle_struct *handle,
 {
 	time_t timestamp_old = 0;
 	time_t timestamp_new = 0;
+	char *snappath_old = NULL;
+	char *snappath_new = NULL;
 
-	if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname,
-					 &timestamp_old, NULL)) {
+	if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle, oldname,
+					 &timestamp_old, NULL, &snappath_old)) {
 		return -1;
 	}
-	if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname,
-					 &timestamp_new, NULL)) {
+	if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle, newname,
+					 &timestamp_new, NULL, &snappath_new)) {
 		return -1;
 	}
 	if ((timestamp_old != 0) || (timestamp_new != 0)) {
 		errno = EROFS;
 		return -1;
 	}
+	/*
+	 * Don't allow symlinks on already converted paths.
+	 */
+	if ((snappath_old != NULL) || (snappath_new != NULL)) {
+		errno = EROFS;
+		return -1;
+	}
 	return SMB_VFS_NEXT_SYMLINK(handle, oldname, newname);
 }
 
@@ -951,19 +973,28 @@ static int shadow_copy2_link(vfs_handle_struct *handle,
 {
 	time_t timestamp_old = 0;
 	time_t timestamp_new = 0;
+	char *snappath_old = NULL;
+	char *snappath_new = NULL;
 
-	if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname,
-					 &timestamp_old, NULL)) {
+	if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle, oldname,
+					 &timestamp_old, NULL, &snappath_old)) {
 		return -1;
 	}
-	if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname,
-					 &timestamp_new, NULL)) {
+	if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle, newname,
+					 &timestamp_new, NULL, &snappath_new)) {
 		return -1;
 	}
 	if ((timestamp_old != 0) || (timestamp_new != 0)) {
 		errno = EROFS;
 		return -1;
 	}
+	/*
+	 * Don't allow links on already converted paths.
+	 */
+	if ((snappath_old != NULL) || (snappath_new != NULL)) {
+		errno = EROFS;
+		return -1;
+	}
 	return SMB_VFS_NEXT_LINK(handle, oldname, newname);
 }
 
-- 
2.7.4