Subject: [PATCH 18/35] s3: VFS: shadow_copy2: Fix module to work with variable current working directory.

From: Jeremy Allison <[email-masked]>
Date: Thu, 26 Jan 2017 10:49:51 -0800

Completely cleans up the horrible shadow_copy2_strip_snapshot()
and adds an explaination of what it's actually trying to do.

* This function does two things.
*
* 1). Checks if an incoming filename is already a
* snapshot converted pathname.
*     If so, it returns the pathname truncated
*     at the snapshot point which will be used
*     as the connectpath, and then does an early return.
*
* 2). Checks if an incoming filename contains an
* SMB-layer @GMT- style timestamp.
*     If so, it strips the timestamp, and returns
*     both the timestamp and the stripped path
*     (making it cwd-relative).

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

Signed-off-by: Jeremy Allison <[email-masked]>
Reviewed-by: Uri Simchoni <[email-masked]>
(backported from commit 128d5f27cd42b0c7efcbe3d28fe3eee881e0734b)
---
 source3/modules/vfs_shadow_copy2.c | 189 ++++++++++++++++++-------------------
 1 file changed, 92 insertions(+), 97 deletions(-)

diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c
index f1d4619a03d..edf7ba23001 100644
--- a/source3/modules/vfs_shadow_copy2.c
+++ b/source3/modules/vfs_shadow_copy2.c
@@ -374,10 +374,21 @@ static int check_for_converted_path(TALLOC_CTX *mem_ctx,
 }
 
 /**
- * Strip a snapshot component from a filename as
- * handed in via the smb layer.
- * Returns the parsed timestamp and the stripped filename.
+ * This function does two things.
+ *
+ * 1). Checks if an incoming filename is already a
+ * snapshot converted pathname.
+ *     If so, it returns the pathname truncated
+ *     at the snapshot point which will be used
+ *     as the connectpath, and then does an early return.
+ *
+ * 2). Checks if an incoming filename contains an
+ * SMB-layer @GMT- style timestamp.
+ *     If so, it strips the timestamp, and returns
+ *     both the timestamp and the stripped path
+ *     (making it cwd-relative).
  */
+
 static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx,
 					struct vfs_handle_struct *handle,
 					const char *orig_name,
@@ -392,62 +403,72 @@ static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx,
 	char *stripped = NULL;
 	size_t rest_len, dst_len;
 	struct shadow_copy2_config *config;
-	const char *snapdir;
-	ssize_t snapdirlen;
 	ptrdiff_t len_before_gmt;
 	const char *name = orig_name;
+	char *abs_path = NULL;
+	bool ret = true;
+	bool already_converted = false;
+	int err = 0;
 
 	SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
 				return false);
 
 	DEBUG(10, (__location__ ": enter path '%s'\n", name));
 
+	abs_path = make_path_absolute(mem_ctx, config, name);
+	if (abs_path == NULL) {
+		ret = false;
+		goto out;
+	}
+	name = abs_path;
+
+	DEBUG(10, (__location__ ": abs path '%s'\n", name));
+
+	err = check_for_converted_path(mem_ctx,
+					handle,
+					config,
+					abs_path,
+					&already_converted,
+					psnappath);
+	if (err != 0) {
+		/* error in conversion. */
+		ret = false;
+		goto out;
+	}
+
+	if (already_converted) {
+		goto out;
+	}
+
+	/*
+	 * From here we're only looking to strip an
+	 * SMB-layer @GMT- token.
+	 */
+
 	p = strstr_m(name, "@GMT-");
 	if (p == NULL) {
 		DEBUG(11, ("@GMT not found\n"));
-		goto no_snapshot;
+		goto out;
 	}
 	if ((p > name) && (p[-1] != '/')) {
 		/* the GMT-token does not start a path-component */
 		DEBUG(10, ("not at start, p=%p, name=%p, p[-1]=%d\n",
 			   p, name, (int)p[-1]));
-		goto no_snapshot;
+		goto out;
 	}
 
-	/*
-	 * Figure out whether we got an already converted string. One
-	 * case where this happens is in a smb2 create call with the
-	 * mxac create blob set. We do the get_acl call on
-	 * fsp->fsp_name, which is already converted. We are converted
-	 * if we got a file name of the form ".snapshots/@GMT-",
-	 * i.e. ".snapshots/" precedes "p".
-	 */
-
-	snapdir = lp_parm_const_string(SNUM(handle->conn), "shadow", "snapdir",
-				       ".snapshots");
-	snapdirlen = strlen(snapdir);
 	len_before_gmt = p - name;
 
-	if ((len_before_gmt >= (snapdirlen + 1)) && (p[-1] == '/')) {
-		const char *parent_snapdir = p - (snapdirlen+1);
-
-		DEBUG(10, ("parent_snapdir = %s\n", parent_snapdir));
-
-		if (strncmp(parent_snapdir, snapdir, snapdirlen) == 0) {
-			DEBUG(10, ("name=%s is already converted\n", name));
-			goto no_snapshot;
-		}
-	}
 	q = strptime(p, GMT_FORMAT, &tm);
 	if (q == NULL) {
 		DEBUG(10, ("strptime failed\n"));
-		goto no_snapshot;
+		goto out;
 	}
 	tm.tm_isdst = -1;
 	timestamp = timegm(&tm);
 	if (timestamp == (time_t)-1) {
 		DEBUG(10, ("timestamp==-1\n"));
-		goto no_snapshot;
+		goto out;
 	}
 	if (q[0] == '\0') {
 		/*
@@ -457,14 +478,33 @@ static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx,
 		 * with a path prefix.
 		 */
 		if (pstripped != NULL) {
+			if (len_before_gmt > 0) {
+				/*
+				 * There is a slash before
+				 * the @GMT-. Remove it.
+				 */
+				len_before_gmt -= 1;
+			}
 			stripped = talloc_strndup(mem_ctx, name, p - name);
 			if (stripped == NULL) {
-				return false;
+				ret = false;
+				goto out;
+			}
+			if (orig_name[0] != '/') {
+				if (make_relative_path(config->shadow_cwd,
+						stripped) == false) {
+					DEBUG(10, (__location__ ": path '%s' "
+						"doesn't start with cwd '%s\n",
+						stripped, config->shadow_cwd));
+						ret = false;
+					errno = ENOENT;
+					goto out;
+				}
 			}
 			*pstripped = stripped;
 		}
 		*ptimestamp = timestamp;
-		return true;
+		goto out;
 	}
 	if (q[0] != '/') {
 		/*
@@ -472,75 +512,18 @@ static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx,
 		 * component continues after the gmt-token.
 		 */
 		DEBUG(10, ("q[0] = %d\n", (int)q[0]));
-		goto no_snapshot;
+		goto out;
 	}
 	q += 1;
 
 	rest_len = strlen(q);
 	dst_len = (p-name) + rest_len;
 
-	if (config->snapdirseverywhere) {
-		char *insert;
-		bool have_insert;
-		insert = shadow_copy2_insert_string(talloc_tos(), handle,
-						    timestamp);
-		if (insert == NULL) {
-			errno = ENOMEM;
-			return false;
-		}
-
-		DEBUG(10, (__location__ ": snapdirseverywhere mode.\n"
-			   "path '%s'.\n"
-			   "insert string '%s'\n", name, insert));
-
-		have_insert = (strstr(name, insert+1) != NULL);
-		DEBUG(10, ("have_insert=%d, name=%s, insert+1=%s\n",
-			   (int)have_insert, name, insert+1));
-		if (have_insert) {
-			DEBUG(10, (__location__ ": insert string '%s' found in "
-				   "path '%s' found in snapdirseverywhere mode "
-				   "==> already converted\n", insert, name));
-			TALLOC_FREE(insert);
-			goto no_snapshot;
-		}
-		TALLOC_FREE(insert);
-	} else {
-		char *snapshot_path;
-		char *s;
-
-		snapshot_path = shadow_copy2_snapshot_path(talloc_tos(),
-							   handle,
-							   timestamp);
-		if (snapshot_path == NULL) {
-			errno = ENOMEM;
-			return false;
-		}
-
-		DEBUG(10, (__location__ " path: '%s'.\n"
-			   "snapshot path: '%s'\n", name, snapshot_path));
-
-		s = strstr(name, snapshot_path);
-		if (s == name) {
-			/*
-			 * this starts with "snapshot_basepath/GMT-Token"
-			 * so it is already a converted absolute
-			 * path. Don't process further.
-			 */
-			DEBUG(10, (__location__ ": path '%s' starts with "
-				   "snapshot path '%s' (not in "
-				   "snapdirseverywhere mode) ==> "
-				   "already converted\n", name, snapshot_path));
-			talloc_free(snapshot_path);
-			goto no_snapshot;
-		}
-		talloc_free(snapshot_path);
-	}
-
 	if (pstripped != NULL) {
 		stripped = talloc_array(mem_ctx, char, dst_len+1);
 		if (stripped == NULL) {
-			errno = ENOMEM;
-			return false;
+			ret = false;
+			goto out;
 		}
 		if (p > name) {
 			memcpy(stripped, name, p-name);
@@ -549,13 +532,25 @@ static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx,
 			memcpy(stripped + (p-name), q, rest_len);
 		}
 		stripped[dst_len] = '\0';
+		if (orig_name[0] != '/') {
+			if (make_relative_path(config->shadow_cwd,
+					stripped) == false) {
+				DEBUG(10, (__location__ ": path '%s' "
+					"doesn't start with cwd '%s\n",
+					stripped, config->shadow_cwd));
+				ret = false;
+				errno = ENOENT;
+				goto out;
+			}
+		}
 		*pstripped = stripped;
 	}
 	*ptimestamp = timestamp;
-	return true;
-no_snapshot:
-	*ptimestamp = 0;
-	return true;
+	ret = true;
+
+  out:
+	TALLOC_FREE(abs_path);
+	return ret;
 }
 
 static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx,
-- 
2.12.0.rc1.440.g5b76565f74-goog