The Samba-Bugzilla – Attachment 12860 Details for
Bug 12531
vfs_shadow_copy2 doesn't cope with server changing directories.
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
git-am fix for master.
shadow_copy_fix13 (text/plain), 74.81 KB, created by
Jeremy Allison
on 2017-01-27 19:25:39 UTC
(
hide
)
Description:
git-am fix for master.
Filename:
MIME Type:
Creator:
Jeremy Allison
Created:
2017-01-27 19:25:39 UTC
Size:
74.81 KB
patch
obsolete
>From 38d3a1f4fd435c45fcf52dfb06d1f9341b7bca7c Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Wed, 11 Jan 2017 16:30:38 -0800 >Subject: [PATCH 01/20] s3: smbd: Correctly canonicalize any incoming shadow > copy path. > >Converts to: > >@GMT-token/path/last_component > >from all incoming path types. Allows shadow_copy modules >to work when current directory is changed after removing >last component. > >Ultimately when the VFS ABI is changed to add a timestamp >to struct smb_filename, this is where the parsing will be >done. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/filename.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 150 insertions(+) > >diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c >index a8cfb55b0f0..efe52a04328 100644 >--- a/source3/smbd/filename.c >+++ b/source3/smbd/filename.c >@@ -220,6 +220,148 @@ static NTSTATUS check_parent_exists(TALLOC_CTX *ctx, > return NT_STATUS_OK; > } > >+/* >+ * Re-order a known good @GMT-token path. >+ */ >+ >+static NTSTATUS rearrange_snapshot_path(struct smb_filename *smb_fname, >+ char *startp, >+ char *endp) >+{ >+ size_t endlen = 0; >+ size_t gmt_len = endp - startp; >+ char gmt_store[gmt_len + 1]; >+ char *parent = NULL; >+ const char *last_component = NULL; >+ char *newstr; >+ bool ret; >+ >+ DBG_DEBUG("|%s| -> ", smb_fname->base_name); >+ >+ /* Save off the @GMT-token. */ >+ memcpy(gmt_store, startp, gmt_len); >+ gmt_store[gmt_len] = '\0'; >+ >+ if (*endp == '/') { >+ /* Remove any trailing '/' */ >+ endp++; >+ } >+ >+ if (*endp == '\0') { >+ /* >+ * @GMT-token was at end of path. >+ * Remove any preceeding '/' >+ */ >+ if (startp > smb_fname->base_name && startp[-1] == '/') { >+ startp--; >+ } >+ } >+ >+ /* Remove @GMT-token from the path. */ >+ endlen = strlen(endp); >+ memmove(startp, endp, endlen + 1); >+ >+ /* Split the remaining path into components. */ >+ ret = parent_dirname(smb_fname, >+ smb_fname->base_name, >+ &parent, >+ &last_component); >+ if (ret == false) { >+ /* Must terminate debug with \n */ >+ DBG_DEBUG("NT_STATUS_NO_MEMORY\n"); >+ return NT_STATUS_NO_MEMORY; >+ } >+ >+ if (ISDOT(parent)) { >+ if (last_component[0] == '\0') { >+ newstr = talloc_strdup(smb_fname, >+ gmt_store); >+ } else { >+ newstr = talloc_asprintf(smb_fname, >+ "%s/%s", >+ gmt_store, >+ last_component); >+ } >+ } else { >+ newstr = talloc_asprintf(smb_fname, >+ "%s/%s/%s", >+ gmt_store, >+ parent, >+ last_component); >+ } >+ >+ TALLOC_FREE(parent); >+ TALLOC_FREE(smb_fname->base_name); >+ smb_fname->base_name = newstr; >+ >+ DBG_DEBUG("|%s|\n", newstr); >+ >+ return NT_STATUS_OK; >+} >+ >+/* >+ * Canonicalize any incoming pathname potentially containining >+ * a @GMT-token into a path that looks like: >+ * >+ * @GMT-YYYY-MM-DD-HH-MM-SS/path/name/components/last_component >+ * >+ * Leaves single path @GMT-token -component alone: >+ * >+ * @GMT-YYYY-MM-DD-HH-MM-SS -> @GMT-YYYY-MM-DD-HH-MM-SS >+ * >+ * Eventually when struct smb_filename is updated and the VFS >+ * ABI is changed this will remove the @GMT-YYYY-MM-DD-HH-MM-SS >+ * and store in the struct smb_filename as a struct timeval field >+ * instead. >+ */ >+ >+static NTSTATUS canonicalize_snapshot_path(struct smb_filename *smb_fname) >+{ >+ char *startp = strchr_m(smb_fname->base_name, '@'); >+ char *endp = NULL; >+ struct tm tm; >+ >+ if (startp == NULL) { >+ /* No @ */ >+ return NT_STATUS_OK; >+ } >+ >+ startp = strstr_m(startp, "@GMT-"); >+ if (startp == NULL) { >+ /* No @ */ >+ return NT_STATUS_OK; >+ } >+ >+ if ((startp > smb_fname->base_name) && (startp[-1] != '/')) { >+ /* the GMT-token does not start a path-component */ >+ return NT_STATUS_OK; >+ } >+ >+ endp = strptime(startp, GMT_FORMAT, &tm); >+ if (endp == NULL) { >+ /* Not a valid timestring. */ >+ return NT_STATUS_OK; >+ } >+ >+ if ( endp[0] == '\0') { >+ return rearrange_snapshot_path(smb_fname, >+ startp, >+ endp); >+ } >+ >+ if (endp[0] != '/') { >+ /* >+ * It is not a complete path component, i.e. the path >+ * component continues after the gmt-token. >+ */ >+ return NT_STATUS_OK; >+ } >+ >+ return rearrange_snapshot_path(smb_fname, >+ startp, >+ endp); >+} >+ > /**************************************************************************** > This routine is called to convert names from the dos namespace to unix > namespace. It needs to handle any case conversions, mangling, format changes, >@@ -356,6 +498,14 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, > goto err; > } > >+ /* Canonicalize any @GMT- paths. */ >+ if (posix_pathnames == false) { >+ status = canonicalize_snapshot_path(smb_fname); >+ if (!NT_STATUS_IS_OK(status)) { >+ goto err; >+ } >+ } >+ > /* > * Large directory fix normalization. If we're case sensitive, and > * the case preserving parameters are set to "no", normalize the case of >-- >2.11.0.483.g087da7b7c-goog > > >From bc8d58215bcad1bd89d4d44ba546a812cdc25d36 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Tue, 17 Jan 2017 11:33:18 -0800 >Subject: [PATCH 02/20] s3: lib: Add canonicalize_absolute_path(). > >Resolves any invalid path components (.) (..) >in an absolute POSIX path. > >We will be re-using this in several places. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/lib/util_path.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++ > source3/lib/util_path.h | 1 + > 2 files changed, 134 insertions(+) > >diff --git a/source3/lib/util_path.c b/source3/lib/util_path.c >index 509ba5ff727..cbad2e15d48 100644 >--- a/source3/lib/util_path.c >+++ b/source3/lib/util_path.c >@@ -93,3 +93,136 @@ char *cache_path(const char *name) > { > return xx_path(name, lp_cache_directory()); > } >+ >+/** >+ * @brief Removes any invalid path components in an absolute POSIX path. >+ * >+ * @param ctx Talloc context to return string. >+ * >+ * @param abs_path Absolute path string to process. >+ * >+ * @retval Pointer to a talloc'ed string containing the absolute full path. >+ **/ >+ >+char *canonicalize_absolute_path(TALLOC_CTX *ctx, const char *abs_path) >+{ >+ char *destname; >+ char *d; >+ const char *s = abs_path; >+ bool start_of_name_component = true; >+ >+ /* Allocate for strlen + '\0' + possible leading '/' */ >+ destname = (char *)talloc_size(ctx, strlen(abs_path) + 2); >+ if (destname == NULL) { >+ return NULL; >+ } >+ d = destname; >+ >+ *d++ = '/'; /* Always start with root. */ >+ >+ while (*s) { >+ if (*s == '/') { >+ /* Eat multiple '/' */ >+ while (*s == '/') { >+ s++; >+ } >+ if ((d > destname + 1) && (*s != '\0')) { >+ *d++ = '/'; >+ } >+ start_of_name_component = true; >+ continue; >+ } >+ >+ if (start_of_name_component) { >+ if ((s[0] == '.') && (s[1] == '.') && >+ (s[2] == '/' || s[2] == '\0')) { >+ /* Uh oh - "/../" or "/..\0" ! */ >+ >+ /* Go past the ../ or .. */ >+ if (s[2] == '/') { >+ s += 3; >+ } else { >+ s += 2; /* Go past the .. */ >+ } >+ >+ /* If we just added a '/' - delete it */ >+ if ((d > destname) && (*(d-1) == '/')) { >+ *(d-1) = '\0'; >+ d--; >+ } >+ >+ /* >+ * Are we at the start ? >+ * Can't go back further if so. >+ */ >+ if (d <= destname) { >+ *d++ = '/'; /* Can't delete root */ >+ continue; >+ } >+ /* Go back one level... */ >+ /* >+ * Decrement d first as d points to >+ * the *next* char to write into. >+ */ >+ for (d--; d > destname; d--) { >+ if (*d == '/') { >+ break; >+ } >+ } >+ /* >+ * We're still at the start of a name >+ * component, just the previous one. >+ */ >+ continue; >+ } else if ((s[0] == '.') && >+ ((s[1] == '\0') || s[1] == '/')) { >+ /* >+ * Component of pathname can't be "." only. >+ * Skip the '.' . >+ */ >+ if (s[1] == '/') { >+ s += 2; >+ } else { >+ s++; >+ } >+ continue; >+ } >+ } >+ >+ if (!(*s & 0x80)) { >+ *d++ = *s++; >+ } else { >+ size_t siz; >+ /* Get the size of the next MB character. */ >+ next_codepoint(s,&siz); >+ switch(siz) { >+ case 5: >+ *d++ = *s++; >+ /*fall through*/ >+ case 4: >+ *d++ = *s++; >+ /*fall through*/ >+ case 3: >+ *d++ = *s++; >+ /*fall through*/ >+ case 2: >+ *d++ = *s++; >+ /*fall through*/ >+ case 1: >+ *d++ = *s++; >+ break; >+ default: >+ break; >+ } >+ } >+ start_of_name_component = false; >+ } >+ *d = '\0'; >+ >+ /* And must not end in '/' */ >+ if (d > destname + 1 && (*(d-1) == '/')) { >+ *(d-1) = '\0'; >+ } >+ >+ return destname; >+} >diff --git a/source3/lib/util_path.h b/source3/lib/util_path.h >index 118a4bed524..16e27926084 100644 >--- a/source3/lib/util_path.h >+++ b/source3/lib/util_path.h >@@ -27,5 +27,6 @@ > char *lock_path(const char *name); > char *state_path(const char *name); > char *cache_path(const char *name); >+char *canonicalize_absolute_path(TALLOC_CTX *ctx, const char *abs_path); > > #endif >-- >2.11.0.483.g087da7b7c-goog > > >From dc2be68ee6b181823025725f11a6cd270b293e91 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 19 Jan 2017 15:18:41 -0800 >Subject: [PATCH 03/20] s3: lib: Fix two old, old bugs in > set_conn_connectpath(), now in canonicalize_absolute_path(). > >Canonicalizing a path of /foo/bar/../baz would return /foo/barbaz >as moving forward 3 characters would delete the / character. > >Canonicalizing /foo/.. would end up as '\0'. > >Test to follow. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/lib/util_path.c | 18 ++++++++++++------ > 1 file changed, 12 insertions(+), 6 deletions(-) > >diff --git a/source3/lib/util_path.c b/source3/lib/util_path.c >index cbad2e15d48..6f58a03ae58 100644 >--- a/source3/lib/util_path.c >+++ b/source3/lib/util_path.c >@@ -138,12 +138,8 @@ char *canonicalize_absolute_path(TALLOC_CTX *ctx, const char *abs_path) > (s[2] == '/' || s[2] == '\0')) { > /* Uh oh - "/../" or "/..\0" ! */ > >- /* Go past the ../ or .. */ >- if (s[2] == '/') { >- s += 3; >- } else { >- s += 2; /* Go past the .. */ >- } >+ /* Go past the .. leaving us on the / or '\0' */ >+ s += 2; > > /* If we just added a '/' - delete it */ > if ((d > destname) && (*(d-1) == '/')) { >@@ -169,6 +165,16 @@ char *canonicalize_absolute_path(TALLOC_CTX *ctx, const char *abs_path) > break; > } > } >+ >+ /* >+ * Are we at the start ? >+ * Can't go back further if so. >+ */ >+ if (d <= destname) { >+ *d++ = '/'; /* Can't delete root */ >+ continue; >+ } >+ > /* > * We're still at the start of a name > * component, just the previous one. >-- >2.11.0.483.g087da7b7c-goog > > >From 68f7fba084b31156d479a4c4cc581be5391643da Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 26 Jan 2017 16:08:42 -0800 >Subject: [PATCH 04/20] s3: smbtorture: Add new local test > LOCAL-CANONICALIZE-PATH > >Tests new canonicalize_absolute_path() function. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/selftest/tests.py | 1 + > source3/torture/torture.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 45 insertions(+) > >diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py >index 4231e1db42c..68cc04741fb 100755 >--- a/source3/selftest/tests.py >+++ b/source3/selftest/tests.py >@@ -125,6 +125,7 @@ local_tests = [ > "LOCAL-MESSAGING-FDPASS2a", > "LOCAL-MESSAGING-FDPASS2b", > "LOCAL-PTHREADPOOL-TEVENT", >+ "LOCAL-CANONICALIZE-PATH", > "LOCAL-hex_encode_buf", > "LOCAL-remove_duplicate_addrs2"] > >diff --git a/source3/torture/torture.c b/source3/torture/torture.c >index 073931e097e..1bd7d6e1393 100644 >--- a/source3/torture/torture.c >+++ b/source3/torture/torture.c >@@ -11020,6 +11020,49 @@ static bool run_local_tdb_writer(int dummy) > return true; > } > >+static bool run_local_canonicalize_path(int dummy) >+{ >+ const char *src[] = { >+ "/foo/..", >+ "/..", >+ "/foo/bar/../baz", >+ "/foo/././", >+ "/../foo", >+ ".././././", >+ ".././././../../../boo", >+ "./..", >+ NULL >+ }; >+ const char *dst[] = { >+ "/", >+ "/", >+ "/foo/baz", >+ "/foo", >+ "/foo", >+ "/", >+ "/boo", >+ "/", >+ NULL >+ }; >+ unsigned int i; >+ >+ for (i = 0; src[i] != NULL; i++) { >+ char *d = canonicalize_absolute_path(talloc_tos(), src[i]); >+ if (d == NULL) { >+ perror("talloc fail\n"); >+ return false; >+ } >+ if (strcmp(d, dst[i]) != 0) { >+ d_fprintf(stderr, >+ "canonicalize missmatch %s -> %s != %s", >+ src[i], d, dst[i]); >+ return false; >+ } >+ talloc_free(d); >+ } >+ return true; >+} >+ > static double create_procs(bool (*fn)(int), bool *result) > { > int i, status; >@@ -11256,6 +11299,7 @@ static struct { > { "LOCAL-DBWRAP-CTDB", run_local_dbwrap_ctdb, 0 }, > { "LOCAL-BENCH-PTHREADPOOL", run_bench_pthreadpool, 0 }, > { "LOCAL-PTHREADPOOL-TEVENT", run_pthreadpool_tevent, 0 }, >+ { "LOCAL-CANONICALIZE-PATH", run_local_canonicalize_path, 0 }, > { "qpathinfo-bufsize", run_qpathinfo_bufsize, 0 }, > {NULL, NULL, 0}}; > >-- >2.11.0.483.g087da7b7c-goog > > >From 43e8a811a1a24c8b352de500e225500d4ba22910 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Tue, 17 Jan 2017 11:35:52 -0800 >Subject: [PATCH 05/20] s3: smbd: Make set_conn_connectpath() call > canonicalize_absolute_path(). > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/service.c | 103 ++----------------------------------------------- > 1 file changed, 3 insertions(+), 100 deletions(-) > >diff --git a/source3/smbd/service.c b/source3/smbd/service.c >index 3308e9dce97..a0ac9dfa2af 100644 >--- a/source3/smbd/service.c >+++ b/source3/smbd/service.c >@@ -31,6 +31,7 @@ > #include "lib/param/loadparm.h" > #include "messages.h" > #include "lib/afs/afs_funcs.h" >+#include "lib/util_path.h" > > static bool canonicalize_connect_path(connection_struct *conn) > { >@@ -47,118 +48,20 @@ static bool canonicalize_connect_path(connection_struct *conn) > /**************************************************************************** > Ensure when setting connectpath it is a canonicalized (no ./ // or ../) > absolute path stating in / and not ending in /. >- Observent people will notice a similarity between this and check_path_syntax :-). > ****************************************************************************/ > > bool set_conn_connectpath(connection_struct *conn, const char *connectpath) > { > char *destname; >- char *d; >- const char *s = connectpath; >- bool start_of_name_component = true; > > if (connectpath == NULL || connectpath[0] == '\0') { > return false; > } > >- /* Allocate for strlen + '\0' + possible leading '/' */ >- destname = (char *)talloc_size(conn, strlen(connectpath) + 2); >- if (!destname) { >+ destname = canonicalize_absolute_path(conn, connectpath); >+ if (destname == NULL) { > return false; > } >- d = destname; >- >- *d++ = '/'; /* Always start with root. */ >- >- while (*s) { >- if (*s == '/') { >- /* Eat multiple '/' */ >- while (*s == '/') { >- s++; >- } >- if ((d > destname + 1) && (*s != '\0')) { >- *d++ = '/'; >- } >- start_of_name_component = True; >- continue; >- } >- >- if (start_of_name_component) { >- if ((s[0] == '.') && (s[1] == '.') && (s[2] == '/' || s[2] == '\0')) { >- /* Uh oh - "/../" or "/..\0" ! */ >- >- /* Go past the ../ or .. */ >- if (s[2] == '/') { >- s += 3; >- } else { >- s += 2; /* Go past the .. */ >- } >- >- /* If we just added a '/' - delete it */ >- if ((d > destname) && (*(d-1) == '/')) { >- *(d-1) = '\0'; >- d--; >- } >- >- /* Are we at the start ? Can't go back further if so. */ >- if (d <= destname) { >- *d++ = '/'; /* Can't delete root */ >- continue; >- } >- /* Go back one level... */ >- /* Decrement d first as d points to the *next* char to write into. */ >- for (d--; d > destname; d--) { >- if (*d == '/') { >- break; >- } >- } >- /* We're still at the start of a name component, just the previous one. */ >- continue; >- } else if ((s[0] == '.') && ((s[1] == '\0') || s[1] == '/')) { >- /* Component of pathname can't be "." only - skip the '.' . */ >- if (s[1] == '/') { >- s += 2; >- } else { >- s++; >- } >- continue; >- } >- } >- >- if (!(*s & 0x80)) { >- *d++ = *s++; >- } else { >- size_t siz; >- /* Get the size of the next MB character. */ >- next_codepoint(s,&siz); >- switch(siz) { >- case 5: >- *d++ = *s++; >- /*fall through*/ >- case 4: >- *d++ = *s++; >- /*fall through*/ >- case 3: >- *d++ = *s++; >- /*fall through*/ >- case 2: >- *d++ = *s++; >- /*fall through*/ >- case 1: >- *d++ = *s++; >- break; >- default: >- break; >- } >- } >- start_of_name_component = false; >- } >- *d = '\0'; >- >- /* And must not end in '/' */ >- if (d > destname + 1 && (*(d-1) == '/')) { >- *(d-1) = '\0'; >- } > > DEBUG(10,("set_conn_connectpath: service %s, connectpath = %s\n", > lp_servicename(talloc_tos(), SNUM(conn)), destname )); >-- >2.11.0.483.g087da7b7c-goog > > >From 8cb15897472d11a330a2954e1e824b96f2864414 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Fri, 20 Jan 2017 11:42:39 -0800 >Subject: [PATCH 06/20] s3: VFS: shadow_copy2: Correctly initialize timestamp > and stripped variables. > >Allow the called functions to be fixed to not touch them on error. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/modules/vfs_shadow_copy2.c | 116 +++++++++++++++++++------------------ > 1 file changed, 61 insertions(+), 55 deletions(-) > >diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c >index 6a25c87b7f7..ed98dd4f8ae 100644 >--- a/source3/modules/vfs_shadow_copy2.c >+++ b/source3/modules/vfs_shadow_copy2.c >@@ -416,10 +416,10 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, > char **pstripped) > { > struct tm tm; >- time_t timestamp; >+ time_t timestamp = 0; > const char *p; > char *q; >- char *stripped; >+ char *stripped = NULL; > size_t rest_len, dst_len; > struct shadow_copy2_private *priv; > const char *snapdir; >@@ -893,8 +893,8 @@ static DIR *shadow_copy2_opendir(vfs_handle_struct *handle, > const char *mask, > uint32_t attr) > { >- time_t timestamp; >- char *stripped; >+ time_t timestamp = 0; >+ char *stripped = NULL; > DIR *ret; > int saved_errno; > char *conv; >@@ -936,7 +936,8 @@ static int shadow_copy2_rename(vfs_handle_struct *handle, > const struct smb_filename *smb_fname_src, > const struct smb_filename *smb_fname_dst) > { >- time_t timestamp_src, timestamp_dst; >+ time_t timestamp_src = 0; >+ time_t timestamp_dst = 0; > > if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, > smb_fname_src->base_name, >@@ -962,7 +963,8 @@ static int shadow_copy2_rename(vfs_handle_struct *handle, > static int shadow_copy2_symlink(vfs_handle_struct *handle, > const char *oldname, const char *newname) > { >- time_t timestamp_old, timestamp_new; >+ time_t timestamp_old = 0; >+ time_t timestamp_new = 0; > > if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname, > ×tamp_old, NULL)) { >@@ -982,7 +984,8 @@ static int shadow_copy2_symlink(vfs_handle_struct *handle, > static int shadow_copy2_link(vfs_handle_struct *handle, > const char *oldname, const char *newname) > { >- time_t timestamp_old, timestamp_new; >+ time_t timestamp_old = 0; >+ time_t timestamp_new = 0; > > if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname, > ×tamp_old, NULL)) { >@@ -1002,8 +1005,9 @@ static int shadow_copy2_link(vfs_handle_struct *handle, > static int shadow_copy2_stat(vfs_handle_struct *handle, > struct smb_filename *smb_fname) > { >- time_t timestamp; >- char *stripped, *tmp; >+ time_t timestamp = 0; >+ char *stripped = NULL; >+ char *tmp; > int ret, saved_errno; > > if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, >@@ -1041,8 +1045,9 @@ static int shadow_copy2_stat(vfs_handle_struct *handle, > static int shadow_copy2_lstat(vfs_handle_struct *handle, > struct smb_filename *smb_fname) > { >- time_t timestamp; >- char *stripped, *tmp; >+ time_t timestamp = 0; >+ char *stripped = NULL; >+ char *tmp; > int ret, saved_errno; > > if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, >@@ -1080,7 +1085,7 @@ static int shadow_copy2_lstat(vfs_handle_struct *handle, > static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp, > SMB_STRUCT_STAT *sbuf) > { >- time_t timestamp; >+ time_t timestamp = 0; > int ret; > > ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf); >@@ -1102,8 +1107,9 @@ static int shadow_copy2_open(vfs_handle_struct *handle, > struct smb_filename *smb_fname, files_struct *fsp, > int flags, mode_t mode) > { >- time_t timestamp; >- char *stripped, *tmp; >+ time_t timestamp = 0; >+ char *stripped = NULL; >+ char *tmp; > int ret, saved_errno; > > if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, >@@ -1138,8 +1144,8 @@ static int shadow_copy2_open(vfs_handle_struct *handle, > static int shadow_copy2_unlink(vfs_handle_struct *handle, > const struct smb_filename *smb_fname) > { >- time_t timestamp; >- char *stripped; >+ time_t timestamp = 0; >+ char *stripped = NULL; > int ret, saved_errno; > struct smb_filename *conv; > >@@ -1173,7 +1179,7 @@ static int shadow_copy2_chmod(vfs_handle_struct *handle, > const struct smb_filename *smb_fname, > mode_t mode) > { >- time_t timestamp; >+ time_t timestamp = 0; > char *stripped = NULL; > int ret, saved_errno; > char *conv = NULL; >@@ -1219,8 +1225,8 @@ static int shadow_copy2_chown(vfs_handle_struct *handle, > uid_t uid, > gid_t gid) > { >- time_t timestamp; >- char *stripped; >+ time_t timestamp = 0; >+ char *stripped = NULL; > int ret, saved_errno; > char *conv = NULL; > struct smb_filename *conv_smb_fname = NULL; >@@ -1261,8 +1267,8 @@ static int shadow_copy2_chown(vfs_handle_struct *handle, > static int shadow_copy2_chdir(vfs_handle_struct *handle, > const char *fname) > { >- time_t timestamp; >- char *stripped; >+ time_t timestamp = 0; >+ char *stripped = NULL; > int ret, saved_errno; > char *conv; > >@@ -1289,8 +1295,8 @@ static int shadow_copy2_ntimes(vfs_handle_struct *handle, > const struct smb_filename *smb_fname, > struct smb_file_time *ft) > { >- time_t timestamp; >- char *stripped; >+ time_t timestamp = 0; >+ char *stripped = NULL; > int ret, saved_errno; > struct smb_filename *conv; > >@@ -1323,8 +1329,8 @@ static int shadow_copy2_ntimes(vfs_handle_struct *handle, > static int shadow_copy2_readlink(vfs_handle_struct *handle, > const char *fname, char *buf, size_t bufsiz) > { >- time_t timestamp; >- char *stripped; >+ time_t timestamp = 0; >+ char *stripped = NULL; > int ret, saved_errno; > char *conv; > >@@ -1350,8 +1356,8 @@ static int shadow_copy2_readlink(vfs_handle_struct *handle, > static int shadow_copy2_mknod(vfs_handle_struct *handle, > const char *fname, mode_t mode, SMB_DEV_T dev) > { >- time_t timestamp; >- char *stripped; >+ time_t timestamp = 0; >+ char *stripped = NULL; > int ret, saved_errno; > char *conv; > >@@ -1377,7 +1383,7 @@ static int shadow_copy2_mknod(vfs_handle_struct *handle, > static char *shadow_copy2_realpath(vfs_handle_struct *handle, > const char *fname) > { >- time_t timestamp; >+ time_t timestamp = 0; > char *stripped = NULL; > char *tmp = NULL; > char *result = NULL; >@@ -1805,8 +1811,8 @@ static NTSTATUS shadow_copy2_fget_nt_acl(vfs_handle_struct *handle, > TALLOC_CTX *mem_ctx, > struct security_descriptor **ppdesc) > { >- time_t timestamp; >- char *stripped; >+ time_t timestamp = 0; >+ char *stripped = NULL; > NTSTATUS status; > char *conv; > struct smb_filename *smb_fname = NULL; >@@ -1849,8 +1855,8 @@ static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle, > TALLOC_CTX *mem_ctx, > struct security_descriptor **ppdesc) > { >- time_t timestamp; >- char *stripped; >+ time_t timestamp = 0; >+ char *stripped = NULL; > NTSTATUS status; > char *conv; > struct smb_filename *conv_smb_fname = NULL; >@@ -1891,8 +1897,8 @@ static int shadow_copy2_mkdir(vfs_handle_struct *handle, > const struct smb_filename *smb_fname, > mode_t mode) > { >- time_t timestamp; >- char *stripped; >+ time_t timestamp = 0; >+ char *stripped = NULL; > int ret, saved_errno; > char *conv; > struct smb_filename *conv_smb_fname = NULL; >@@ -1932,8 +1938,8 @@ static int shadow_copy2_mkdir(vfs_handle_struct *handle, > static int shadow_copy2_rmdir(vfs_handle_struct *handle, > const struct smb_filename *smb_fname) > { >- time_t timestamp; >- char *stripped; >+ time_t timestamp = 0; >+ char *stripped = NULL; > int ret, saved_errno; > char *conv; > struct smb_filename *conv_smb_fname = NULL; >@@ -1973,8 +1979,8 @@ static int shadow_copy2_rmdir(vfs_handle_struct *handle, > static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname, > unsigned int flags) > { >- time_t timestamp; >- char *stripped; >+ time_t timestamp = 0; >+ char *stripped = NULL; > int ret, saved_errno; > char *conv; > >@@ -2001,8 +2007,8 @@ static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle, > const char *fname, const char *aname, > void *value, size_t size) > { >- time_t timestamp; >- char *stripped; >+ time_t timestamp = 0; >+ char *stripped = NULL; > ssize_t ret; > int saved_errno; > char *conv; >@@ -2031,8 +2037,8 @@ static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle, > const char *fname, > char *list, size_t size) > { >- time_t timestamp; >- char *stripped; >+ time_t timestamp = 0; >+ char *stripped = NULL; > ssize_t ret; > int saved_errno; > char *conv; >@@ -2059,8 +2065,8 @@ static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle, > static int shadow_copy2_removexattr(vfs_handle_struct *handle, > const char *fname, const char *aname) > { >- time_t timestamp; >- char *stripped; >+ time_t timestamp = 0; >+ char *stripped = NULL; > int ret, saved_errno; > char *conv; > >@@ -2088,8 +2094,8 @@ static int shadow_copy2_setxattr(struct vfs_handle_struct *handle, > const char *aname, const void *value, > size_t size, int flags) > { >- time_t timestamp; >- char *stripped; >+ time_t timestamp = 0; >+ char *stripped = NULL; > ssize_t ret; > int saved_errno; > char *conv; >@@ -2118,8 +2124,8 @@ static int shadow_copy2_chmod_acl(vfs_handle_struct *handle, > const struct smb_filename *smb_fname, > mode_t mode) > { >- time_t timestamp; >- char *stripped; >+ time_t timestamp = 0; >+ char *stripped = NULL; > ssize_t ret; > int saved_errno; > char *conv = NULL; >@@ -2164,8 +2170,8 @@ static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle, > TALLOC_CTX *mem_ctx, > char **found_name) > { >- time_t timestamp; >- char *stripped; >+ time_t timestamp = 0; >+ char *stripped = NULL; > ssize_t ret; > int saved_errno; > char *conv; >@@ -2203,7 +2209,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; >@@ -2278,8 +2284,8 @@ static uint64_t shadow_copy2_disk_free(vfs_handle_struct *handle, > const char *path, uint64_t *bsize, > uint64_t *dfree, uint64_t *dsize) > { >- time_t timestamp; >- char *stripped; >+ time_t timestamp = 0; >+ char *stripped = NULL; > ssize_t ret; > int saved_errno; > char *conv; >@@ -2312,8 +2318,8 @@ static int shadow_copy2_get_quota(vfs_handle_struct *handle, const char *path, > enum SMB_QUOTA_TYPE qtype, unid_t id, > SMB_DISK_QUOTA *dq) > { >- time_t timestamp; >- char *stripped; >+ time_t timestamp = 0; >+ char *stripped = NULL; > int ret; > int saved_errno; > char *conv; >-- >2.11.0.483.g087da7b7c-goog > > >From 636db94bb48c01d9a3708478b27819fa6f480c15 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Fri, 20 Jan 2017 11:45:54 -0800 >Subject: [PATCH 07/20] s3: VFS: shadow_copy2: Ensure pathnames for parameters > are correctly relative and terminated. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/modules/vfs_shadow_copy2.c | 5 +++++ > 1 file changed, 5 insertions(+) > >diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c >index ed98dd4f8ae..41d2a1fc875 100644 >--- a/source3/modules/vfs_shadow_copy2.c >+++ b/source3/modules/vfs_shadow_copy2.c >@@ -2626,6 +2626,11 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, > } > } > >+ trim_string(config->mount_point, NULL, "/"); >+ trim_string(config->rel_connectpath, "/", "/"); >+ trim_string(config->snapdir, NULL, "/"); >+ trim_string(config->snapshot_basepath, NULL, "/"); >+ > DEBUG(10, ("shadow_copy2_connect: configuration:\n" > " share root: '%s'\n" > " mountpoint: '%s'\n" >-- >2.11.0.483.g087da7b7c-goog > > >From 80acb8444aefe775b1297de4578963cfc24b3aca Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Fri, 20 Jan 2017 11:48:40 -0800 >Subject: [PATCH 08/20] s3: VFS: shadow_copy2: Fix length comparison to ensure > we don't overstep a length. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531 > >Signed-off-by: Jeremy Allison <jra@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 41d2a1fc875..6896a163530 100644 >--- a/source3/modules/vfs_shadow_copy2.c >+++ b/source3/modules/vfs_shadow_copy2.c >@@ -2588,7 +2588,7 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, > } > > if (config->rel_connectpath == NULL && >- strlen(basedir) != strlen(handle->conn->connectpath)) { >+ strlen(basedir) < strlen(handle->conn->connectpath)) { > config->rel_connectpath = talloc_strdup(config, > handle->conn->connectpath + strlen(basedir)); > if (config->rel_connectpath == NULL) { >-- >2.11.0.483.g087da7b7c-goog > > >From ba752d82157534d857424908bbb4c39ad520a8dd Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Fri, 20 Jan 2017 11:50:49 -0800 >Subject: [PATCH 09/20] s3: VFS: shadow_copy2: Add two new variables to the > private data. Not yet used. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/modules/vfs_shadow_copy2.c | 3 +++ > 1 file changed, 3 insertions(+) > >diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c >index 6896a163530..df49a705079 100644 >--- a/source3/modules/vfs_shadow_copy2.c >+++ b/source3/modules/vfs_shadow_copy2.c >@@ -74,6 +74,9 @@ struct shadow_copy2_snaplist_info { > struct shadow_copy2_private { > struct shadow_copy2_config *config; > struct shadow_copy2_snaplist_info *snaps; >+ char *shadow_cwd; /* Absolute $cwd path. */ >+ /* Absolute connectpath - can vary depending on $cwd. */ >+ char *shadow_connectpath; > }; > > static int shadow_copy2_get_shadow_copy_data( >-- >2.11.0.483.g087da7b7c-goog > > >From df79f345a8cd83aba980964792f16a63ccbd641d Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Fri, 20 Jan 2017 11:54:56 -0800 >Subject: [PATCH 10/20] s3: VFS: shadow_copy2: Add a wrapper function to call > the original shadow_copy2_strip_snapshot(). > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531 > >Allows an extra (currently unused) parameter to be added. > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/modules/vfs_shadow_copy2.c | 19 +++++++++++++++++-- > 1 file changed, 17 insertions(+), 2 deletions(-) > >diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c >index df49a705079..2afc2b102bc 100644 >--- a/source3/modules/vfs_shadow_copy2.c >+++ b/source3/modules/vfs_shadow_copy2.c >@@ -412,11 +412,12 @@ static char *shadow_copy2_snapshot_path(TALLOC_CTX *mem_ctx, > * handed in via the smb layer. > * Returns the parsed timestamp and the stripped filename. > */ >-static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, >+static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx, > struct vfs_handle_struct *handle, > const char *name, > time_t *ptimestamp, >- char **pstripped) >+ char **pstripped, >+ char **psnappath) > { > struct tm tm; > time_t timestamp = 0; >@@ -598,6 +599,20 @@ no_snapshot: > return true; > } > >+static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, >+ struct vfs_handle_struct *handle, >+ const char *orig_name, >+ time_t *ptimestamp, >+ char **pstripped) >+{ >+ return shadow_copy2_strip_snapshot_internal(mem_ctx, >+ handle, >+ orig_name, >+ ptimestamp, >+ pstripped, >+ NULL); >+} >+ > static char *shadow_copy2_find_mount_point(TALLOC_CTX *mem_ctx, > vfs_handle_struct *handle) > { >-- >2.11.0.483.g087da7b7c-goog > > >From 75c59e2fc1c1018bfcdbddeb32a7ac3ff5b991e2 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Fri, 20 Jan 2017 11:56:21 -0800 >Subject: [PATCH 11/20] s3: VFS: shadow_copy2: Change a parameter name. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531 > >Allows easy substitution later. > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/modules/vfs_shadow_copy2.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > >diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c >index 2afc2b102bc..e1e219141eb 100644 >--- a/source3/modules/vfs_shadow_copy2.c >+++ b/source3/modules/vfs_shadow_copy2.c >@@ -414,7 +414,7 @@ static char *shadow_copy2_snapshot_path(TALLOC_CTX *mem_ctx, > */ > static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx, > struct vfs_handle_struct *handle, >- const char *name, >+ const char *orig_name, > time_t *ptimestamp, > char **pstripped, > char **psnappath) >@@ -429,6 +429,7 @@ static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx, > const char *snapdir; > ssize_t snapdirlen; > ptrdiff_t len_before_gmt; >+ const char *name = orig_name; > > SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private, > return false); >-- >2.11.0.483.g087da7b7c-goog > > >From 02d66bbc22c856253e3ef619328bd144d4ce37e5 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Fri, 20 Jan 2017 12:00:08 -0800 >Subject: [PATCH 12/20] s3: VFS: shadow_copy2: Add two currently unused > functions to make pathnames absolute or relative to $cwd. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/modules/vfs_shadow_copy2.c | 45 ++++++++++++++++++++++++++++++++++++++ > 1 file changed, 45 insertions(+) > >diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c >index e1e219141eb..d3179de9928 100644 >--- a/source3/modules/vfs_shadow_copy2.c >+++ b/source3/modules/vfs_shadow_copy2.c >@@ -35,6 +35,7 @@ > #include "system/filesys.h" > #include "include/ntioctl.h" > #include "util_tdb.h" >+#include "lib/util_path.h" > > struct shadow_copy2_config { > char *gmt_format; >@@ -407,6 +408,50 @@ static char *shadow_copy2_snapshot_path(TALLOC_CTX *mem_ctx, > return result; > } > >+static char *make_path_absolute(TALLOC_CTX *mem_ctx, >+ struct shadow_copy2_private *priv, >+ const char *name) >+{ >+ char *newpath = NULL; >+ char *abs_path = NULL; >+ >+ if (name[0] != '/') { >+ newpath = talloc_asprintf(mem_ctx, >+ "%s/%s", >+ priv->shadow_cwd, >+ name); >+ if (newpath == NULL) { >+ return NULL; >+ } >+ name = newpath; >+ } >+ abs_path = canonicalize_absolute_path(mem_ctx, name); >+ TALLOC_FREE(newpath); >+ return abs_path; >+} >+ >+/* Return a $cwd-relative path. */ >+static bool make_relative_path(const char *cwd, char *abs_path) >+{ >+ size_t cwd_len = strlen(cwd); >+ size_t abs_len = strlen(abs_path); >+ >+ if (abs_len < cwd_len) { >+ return false; >+ } >+ if (memcmp(abs_path, cwd, cwd_len) != 0) { >+ return false; >+ } >+ if (abs_path[cwd_len] != '/' && abs_path[cwd_len] != '\0') { >+ return false; >+ } >+ if (abs_path[cwd_len] == '/') { >+ cwd_len++; >+ } >+ memmove(abs_path, &abs_path[cwd_len], abs_len + 1 - cwd_len); >+ return true; >+} >+ > /** > * Strip a snapshot component from a filename as > * handed in via the smb layer. >-- >2.11.0.483.g087da7b7c-goog > > >From ada02058c805c94768bfba0ab64ac4eabacd38e8 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Fri, 20 Jan 2017 12:06:55 -0800 >Subject: [PATCH 13/20] s3: VFS: shadow_copy2: Fix chdir to store off the > needed private variables. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531 > >This is not yet used, the users of this will be added later. > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/modules/vfs_shadow_copy2.c | 81 ++++++++++++++++++++++++++++++++------ > 1 file changed, 68 insertions(+), 13 deletions(-) > >diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c >index d3179de9928..2d1b1e67fdb 100644 >--- a/source3/modules/vfs_shadow_copy2.c >+++ b/source3/modules/vfs_shadow_copy2.c >@@ -1328,30 +1328,85 @@ static int shadow_copy2_chown(vfs_handle_struct *handle, > return ret; > } > >+static void store_cwd_data(vfs_handle_struct *handle, >+ const char *connectpath) >+{ >+ struct shadow_copy2_private *priv = NULL; >+ char *cwd = NULL; >+ >+ SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private, >+ return); >+ >+ TALLOC_FREE(priv->shadow_cwd); >+ cwd = SMB_VFS_NEXT_GETWD(handle); >+ if (cwd == NULL) { >+ smb_panic("getwd failed\n"); >+ } >+ DBG_DEBUG("shadow cwd = %s\n", cwd); >+ priv->shadow_cwd = talloc_strdup(priv, cwd); >+ SAFE_FREE(cwd); >+ if (priv->shadow_cwd == NULL) { >+ smb_panic("talloc failed\n"); >+ } >+ TALLOC_FREE(priv->shadow_connectpath); >+ if (connectpath) { >+ DBG_DEBUG("shadow conectpath = %s\n", connectpath); >+ priv->shadow_connectpath = talloc_strdup(priv, connectpath); >+ if (priv->shadow_connectpath == NULL) { >+ smb_panic("talloc failed\n"); >+ } >+ } >+} >+ > static int shadow_copy2_chdir(vfs_handle_struct *handle, > const char *fname) > { > time_t timestamp = 0; > char *stripped = NULL; >- int ret, saved_errno; >- char *conv; >+ char *snappath = NULL; >+ int ret = -1; >+ int saved_errno = 0; >+ char *conv = NULL; >+ size_t rootpath_len = 0; > >- if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, >- ×tamp, &stripped)) { >+ if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle, fname, >+ ×tamp, &stripped, &snappath)) { > return -1; > } >- if (timestamp == 0) { >- return SMB_VFS_NEXT_CHDIR(handle, fname); >+ if (stripped != NULL) { >+ conv = shadow_copy2_do_convert(talloc_tos(), >+ handle, >+ stripped, >+ timestamp, >+ &rootpath_len); >+ TALLOC_FREE(stripped); >+ if (conv == NULL) { >+ return -1; >+ } >+ fname = conv; > } >- conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp); >- TALLOC_FREE(stripped); >- if (conv == NULL) { >- return -1; >+ >+ ret = SMB_VFS_NEXT_CHDIR(handle, fname); >+ if (ret == -1) { >+ saved_errno = errno; > } >- ret = SMB_VFS_NEXT_CHDIR(handle, conv); >- saved_errno = errno; >+ >+ if (ret == 0) { >+ if (conv != NULL && rootpath_len != 0) { >+ conv[rootpath_len] = '\0'; >+ } else if (snappath != 0) { >+ TALLOC_FREE(conv); >+ conv = snappath; >+ } >+ store_cwd_data(handle, conv); >+ } >+ >+ TALLOC_FREE(stripped); > TALLOC_FREE(conv); >- errno = saved_errno; >+ >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return ret; > } > >-- >2.11.0.483.g087da7b7c-goog > > >From aaf86fac9aa4edb76f0e336a2b7e0493bcddd7fd Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Fri, 20 Jan 2017 12:09:08 -0800 >Subject: [PATCH 14/20] s3: VFS: Allow shadow_copy2_connectpath() to return the > cached path derived from $cwd. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/modules/vfs_shadow_copy2.c | 10 ++++++++++ > 1 file changed, 10 insertions(+) > >diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c >index 2d1b1e67fdb..31f36a533f9 100644 >--- a/source3/modules/vfs_shadow_copy2.c >+++ b/source3/modules/vfs_shadow_copy2.c >@@ -2335,9 +2335,19 @@ static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle, > char *parent_dir = NULL; > int saved_errno; > size_t rootpath_len = 0; >+ struct shadow_copy2_private *priv = NULL; >+ >+ SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private, >+ return NULL); > > DBG_DEBUG("Calc connect path for [%s]\n", fname); > >+ if (priv->shadow_connectpath != NULL) { >+ DBG_DEBUG("cached connect path is [%s]\n", >+ priv->shadow_connectpath); >+ return priv->shadow_connectpath; >+ } >+ > if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, > ×tamp, &stripped)) { > goto done; >-- >2.11.0.483.g087da7b7c-goog > > >From 63df63820b803049750558567965b41dc32b95f7 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 26 Jan 2017 10:24:52 -0800 >Subject: [PATCH 15/20] s3: VFS: Ensure shadow:format cannot contain a / path > separator. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/modules/vfs_shadow_copy2.c | 9 +++++++++ > 1 file changed, 9 insertions(+) > >diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c >index 31f36a533f9..2206edefccc 100644 >--- a/source3/modules/vfs_shadow_copy2.c >+++ b/source3/modules/vfs_shadow_copy2.c >@@ -2533,6 +2533,15 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, > return -1; > } > >+ /* config->gmt_format must not contain a path separator. */ >+ if (strchr(config->gmt_format, '/') != NULL) { >+ DEBUG(0, ("shadow:format %s must not contain a /" >+ "character. Unable to initialize module.\n", >+ config->gmt_format)); >+ errno = EINVAL; >+ return -1; >+ } >+ > config->use_sscanf = lp_parm_bool(SNUM(handle->conn), > "shadow", "sscanf", false); > >-- >2.11.0.483.g087da7b7c-goog > > >From 8050e82f619d10cd52055080fde34a6089750add Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 26 Jan 2017 10:35:50 -0800 >Subject: [PATCH 16/20] s3: VFS: Add utility function > check_for_converted_path(). > >Detects an already converted path. Not yet used. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/modules/vfs_shadow_copy2.c | 108 +++++++++++++++++++++++++++++++++++++ > 1 file changed, 108 insertions(+) > >diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c >index 2206edefccc..d6100ac5bb2 100644 >--- a/source3/modules/vfs_shadow_copy2.c >+++ b/source3/modules/vfs_shadow_copy2.c >@@ -452,6 +452,114 @@ static bool make_relative_path(const char *cwd, char *abs_path) > return true; > } > >+static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle, >+ const char *name, >+ char *gmt, size_t gmt_len); >+ >+/* >+ * Check 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. >+ */ >+ >+static int check_for_converted_path(TALLOC_CTX *mem_ctx, >+ struct vfs_handle_struct *handle, >+ struct shadow_copy2_private *priv, >+ char *abs_path, >+ bool *ppath_already_converted, >+ char **pconnectpath) >+{ >+ size_t snapdirlen = 0; >+ char *p = strstr_m(abs_path, priv->config->snapdir); >+ char *q = NULL; >+ char *connect_path = NULL; >+ char snapshot[GMT_NAME_LEN+1]; >+ >+ *ppath_already_converted = false; >+ >+ if (p == NULL) { >+ /* Must at least contain shadow:snapdir. */ >+ return 0; >+ } >+ >+ if (priv->config->snapdir[0] == '/' && >+ p != abs_path) { >+ /* Absolute shadow:snapdir must be at the start. */ >+ return 0; >+ } >+ >+ snapdirlen = strlen(priv->config->snapdir); >+ if (p[snapdirlen] != '/') { >+ /* shadow:snapdir must end as a separate component. */ >+ return 0; >+ } >+ >+ if (p > abs_path && p[-1] != '/') { >+ /* shadow:snapdir must start as a separate component. */ >+ return 0; >+ } >+ >+ p += snapdirlen; >+ p++; /* Move past the / */ >+ >+ /* >+ * Need to return up to the next path >+ * component after the time. >+ * This will be used as the connectpath. >+ */ >+ q = strchr(p, '/'); >+ if (q == NULL) { >+ /* >+ * No next path component. >+ * Use entire string. >+ */ >+ connect_path = talloc_strdup(mem_ctx, >+ abs_path); >+ } else { >+ connect_path = talloc_strndup(mem_ctx, >+ abs_path, >+ q - abs_path); >+ } >+ if (connect_path == NULL) { >+ return ENOMEM; >+ } >+ >+ /* >+ * Point p at the same offset in connect_path as >+ * it is in abs_path. >+ */ >+ >+ p = &connect_path[p - abs_path]; >+ >+ /* >+ * Now ensure there is a time string at p. >+ * The SMB-format @GMT-token string is returned >+ * in snapshot. >+ */ >+ >+ if (!shadow_copy2_snapshot_to_gmt(handle, >+ p, >+ snapshot, >+ sizeof(snapshot))) { >+ TALLOC_FREE(connect_path); >+ return 0; >+ } >+ >+ if (pconnectpath != NULL) { >+ *pconnectpath = connect_path; >+ } >+ >+ *ppath_already_converted = true; >+ >+ DBG_DEBUG("path |%s| is already converted. " >+ "connect path = |%s|\n", >+ abs_path, >+ connect_path); >+ >+ return 0; >+} >+ > /** > * Strip a snapshot component from a filename as > * handed in via the smb layer. >-- >2.11.0.483.g087da7b7c-goog > > >From 78617fbfe88c226e3260b9ee7ea7c489cef515a4 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 26 Jan 2017 10:49:51 -0800 >Subject: [PATCH 17/20] s3: VFS: shadow_copy2: Fix module to work with variable > current working directory. > >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 <jra@samba.org> >--- > source3/modules/vfs_shadow_copy2.c | 182 +++++++++++++++++-------------------- > 1 file changed, 85 insertions(+), 97 deletions(-) > >diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c >index d6100ac5bb2..f116c553ac4 100644 >--- a/source3/modules/vfs_shadow_copy2.c >+++ b/source3/modules/vfs_shadow_copy2.c >@@ -561,10 +561,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, >@@ -579,62 +590,72 @@ static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx, > char *stripped = NULL; > size_t rest_len, dst_len; > struct shadow_copy2_private *priv; >- 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, priv, struct shadow_copy2_private, > return false); > > DEBUG(10, (__location__ ": enter path '%s'\n", name)); > >+ abs_path = make_path_absolute(mem_ctx, priv, 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, >+ priv, >+ 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') { > /* >@@ -654,12 +675,24 @@ static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx, > stripped = talloc_strndup(mem_ctx, name, > len_before_gmt); > if (stripped == NULL) { >- return false; >+ ret = false; >+ goto out; >+ } >+ if (orig_name[0] != '/') { >+ if (make_relative_path(priv->shadow_cwd, >+ stripped) == false) { >+ DEBUG(10, (__location__ ": path '%s' " >+ "doesn't start with cwd '%s\n", >+ stripped, priv->shadow_cwd)); >+ ret = false; >+ errno = ENOENT; >+ goto out; >+ } > } > *pstripped = stripped; > } > *ptimestamp = timestamp; >- return true; >+ goto out; > } > if (q[0] != '/') { > /* >@@ -667,75 +700,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 = len_before_gmt + rest_len; > >- if (priv->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, len_before_gmt); >@@ -744,13 +720,25 @@ static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx, > memcpy(stripped + len_before_gmt, q, rest_len); > } > stripped[dst_len] = '\0'; >+ if (orig_name[0] != '/') { >+ if (make_relative_path(priv->shadow_cwd, >+ stripped) == false) { >+ DEBUG(10, (__location__ ": path '%s' " >+ "doesn't start with cwd '%s\n", >+ stripped, priv->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.11.0.483.g087da7b7c-goog > > >From 8f16362754399c38654ebeef2df794352cb6afcc Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Mon, 23 Jan 2017 10:06:44 -0800 >Subject: [PATCH 18/20] s3: VFS: shadow_copy2: Fix a memory leak in the > connectpath function. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/modules/vfs_shadow_copy2.c | 17 +++++++++++++++++ > 1 file changed, 17 insertions(+) > >diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c >index f116c553ac4..137dad8bf4f 100644 >--- a/source3/modules/vfs_shadow_copy2.c >+++ b/source3/modules/vfs_shadow_copy2.c >@@ -78,6 +78,8 @@ struct shadow_copy2_private { > char *shadow_cwd; /* Absolute $cwd path. */ > /* Absolute connectpath - can vary depending on $cwd. */ > char *shadow_connectpath; >+ /* malloc'ed realpath return. */ >+ char *shadow_realpath; > }; > > static int shadow_copy2_get_shadow_copy_data( >@@ -2494,6 +2496,13 @@ static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle, > goto done; > } > >+ /* >+ * SMB_VFS_NEXT_REALPATH returns a malloc'ed string. >+ * Don't leak memory. >+ */ >+ SAFE_FREE(priv->shadow_realpath); >+ priv->shadow_realpath = result; >+ > DBG_DEBUG("connect path is [%s]\n", result); > > done: >@@ -2572,6 +2581,12 @@ static int shadow_copy2_get_quota(vfs_handle_struct *handle, const char *path, > return ret; > } > >+static int shadow_copy2_private_destructor(struct shadow_copy2_private *priv) >+{ >+ SAFE_FREE(priv->shadow_realpath); >+ return 0; >+} >+ > static int shadow_copy2_connect(struct vfs_handle_struct *handle, > const char *service, const char *user) > { >@@ -2603,6 +2618,8 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, > return -1; > } > >+ talloc_set_destructor(priv, shadow_copy2_private_destructor); >+ > priv->snaps = talloc_zero(priv, struct shadow_copy2_snaplist_info); > if (priv->snaps == NULL) { > DBG_ERR("talloc_zero() failed\n"); >-- >2.11.0.483.g087da7b7c-goog > > >From 8261ddb32c3ec9972294e3a328f58bb310df6015 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Mon, 23 Jan 2017 10:20:13 -0800 >Subject: [PATCH 19/20] s3: VFS: shadow_copy2: Fix usage of saved_errno to only > set errno on error. > >Rationale: > >VFS calls must act like their POSIX equivalents, and the POSIX versions >*only* set errno on a failure. There is actually code in the upper smbd >layers that depends on errno being correct on a fail return from a VFS call. > >For a compound VFS module like this, a common pattern is : > >SMB_VFS_CALL_X() >{ > int ret; > > syscall1(); > ret = syscall2(); > syscall3(); > > return ret; >} > >Where if *any* of the contained syscallX()'s fail, they'll set errno. >However, the actual errno we should return is *only* the one returned >if syscall2() fails (the others are lstat's checking for existence etc.). > >So what we should do to correctly return only the errno from syscall2() is: > >SMB_VFS_CALL_X() >{ > int ret; > int saved_errno = 0; > > syscall1() > > ret = syscall2(); > if (ret == -1) { > saved_errno = errno; > } > syscall3() > > if (saved_errno != 0) { > errno = saved_errno; > } > return ret; >} > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/modules/vfs_shadow_copy2.c | 254 ++++++++++++++++++++++++++----------- > 1 file changed, 182 insertions(+), 72 deletions(-) > >diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c >index 137dad8bf4f..f2a80f4b456 100644 >--- a/source3/modules/vfs_shadow_copy2.c >+++ b/source3/modules/vfs_shadow_copy2.c >@@ -808,7 +808,8 @@ static char *shadow_copy2_do_convert(TALLOC_CTX *mem_ctx, > char *insert = NULL; > char *converted = NULL; > size_t insertlen, connectlen = 0; >- int i, saved_errno; >+ int saved_errno = 0; >+ int i; > size_t min_offset; > struct shadow_copy2_config *config; > struct shadow_copy2_private *priv; >@@ -994,12 +995,16 @@ static char *shadow_copy2_do_convert(TALLOC_CTX *mem_ctx, > errno = ENOENT; > } > fail: >- saved_errno = errno; >+ if (result == NULL) { >+ saved_errno = errno; >+ } > TALLOC_FREE(converted); > TALLOC_FREE(insert); > TALLOC_FREE(slashes); > TALLOC_FREE(path); >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return result; > } > >@@ -1058,7 +1063,7 @@ static DIR *shadow_copy2_opendir(vfs_handle_struct *handle, > time_t timestamp = 0; > char *stripped = NULL; > DIR *ret; >- int saved_errno; >+ int saved_errno = 0; > char *conv; > struct smb_filename *conv_smb_fname = NULL; > >@@ -1087,10 +1092,14 @@ static DIR *shadow_copy2_opendir(vfs_handle_struct *handle, > return NULL; > } > ret = SMB_VFS_NEXT_OPENDIR(handle, conv_smb_fname, mask, attr); >- saved_errno = errno; >+ if (ret == NULL) { >+ saved_errno = errno; >+ } > TALLOC_FREE(conv); > TALLOC_FREE(conv_smb_fname); >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return ret; > } > >@@ -1170,7 +1179,8 @@ static int shadow_copy2_stat(vfs_handle_struct *handle, > time_t timestamp = 0; > char *stripped = NULL; > char *tmp; >- int ret, saved_errno; >+ int saved_errno = 0; >+ int ret; > > if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, > smb_fname->base_name, >@@ -1192,7 +1202,9 @@ static int shadow_copy2_stat(vfs_handle_struct *handle, > } > > ret = SMB_VFS_NEXT_STAT(handle, smb_fname); >- saved_errno = errno; >+ if (ret == -1) { >+ saved_errno = errno; >+ } > > TALLOC_FREE(smb_fname->base_name); > smb_fname->base_name = tmp; >@@ -1200,7 +1212,9 @@ static int shadow_copy2_stat(vfs_handle_struct *handle, > if (ret == 0) { > convert_sbuf(handle, smb_fname->base_name, &smb_fname->st); > } >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return ret; > } > >@@ -1210,7 +1224,8 @@ static int shadow_copy2_lstat(vfs_handle_struct *handle, > time_t timestamp = 0; > char *stripped = NULL; > char *tmp; >- int ret, saved_errno; >+ int saved_errno = 0; >+ int ret; > > if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, > smb_fname->base_name, >@@ -1232,7 +1247,9 @@ static int shadow_copy2_lstat(vfs_handle_struct *handle, > } > > ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname); >- saved_errno = errno; >+ if (ret == -1) { >+ saved_errno = errno; >+ } > > TALLOC_FREE(smb_fname->base_name); > smb_fname->base_name = tmp; >@@ -1240,7 +1257,9 @@ static int shadow_copy2_lstat(vfs_handle_struct *handle, > if (ret == 0) { > convert_sbuf(handle, smb_fname->base_name, &smb_fname->st); > } >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return ret; > } > >@@ -1272,7 +1291,8 @@ static int shadow_copy2_open(vfs_handle_struct *handle, > time_t timestamp = 0; > char *stripped = NULL; > char *tmp; >- int ret, saved_errno; >+ int saved_errno = 0; >+ int ret; > > if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, > smb_fname->base_name, >@@ -1294,12 +1314,16 @@ static int shadow_copy2_open(vfs_handle_struct *handle, > } > > ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode); >- saved_errno = errno; >+ if (ret == -1) { >+ saved_errno = errno; >+ } > > TALLOC_FREE(smb_fname->base_name); > smb_fname->base_name = tmp; > >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return ret; > } > >@@ -1308,7 +1332,8 @@ static int shadow_copy2_unlink(vfs_handle_struct *handle, > { > time_t timestamp = 0; > char *stripped = NULL; >- int ret, saved_errno; >+ int saved_errno = 0; >+ int ret; > struct smb_filename *conv; > > if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, >@@ -1331,9 +1356,13 @@ static int shadow_copy2_unlink(vfs_handle_struct *handle, > return -1; > } > ret = SMB_VFS_NEXT_UNLINK(handle, conv); >- saved_errno = errno; >+ if (ret == -1) { >+ saved_errno = errno; >+ } > TALLOC_FREE(conv); >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return ret; > } > >@@ -1343,7 +1372,8 @@ static int shadow_copy2_chmod(vfs_handle_struct *handle, > { > time_t timestamp = 0; > char *stripped = NULL; >- int ret, saved_errno; >+ int saved_errno = 0; >+ int ret; > char *conv = NULL; > struct smb_filename *conv_smb_fname; > >@@ -1375,10 +1405,14 @@ static int shadow_copy2_chmod(vfs_handle_struct *handle, > } > > ret = SMB_VFS_NEXT_CHMOD(handle, conv_smb_fname, mode); >- saved_errno = errno; >+ if (ret == -1) { >+ saved_errno = errno; >+ } > TALLOC_FREE(conv); > TALLOC_FREE(conv_smb_fname); >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return ret; > } > >@@ -1389,7 +1423,8 @@ static int shadow_copy2_chown(vfs_handle_struct *handle, > { > time_t timestamp = 0; > char *stripped = NULL; >- int ret, saved_errno; >+ int saved_errno = 0; >+ int ret; > char *conv = NULL; > struct smb_filename *conv_smb_fname = NULL; > >@@ -1419,10 +1454,14 @@ static int shadow_copy2_chown(vfs_handle_struct *handle, > return -1; > } > ret = SMB_VFS_NEXT_CHOWN(handle, conv_smb_fname, uid, gid); >- saved_errno = errno; >+ if (ret == -1) { >+ saved_errno = errno; >+ } > TALLOC_FREE(conv); > TALLOC_FREE(conv_smb_fname); >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return ret; > } > >@@ -1514,7 +1553,8 @@ static int shadow_copy2_ntimes(vfs_handle_struct *handle, > { > time_t timestamp = 0; > char *stripped = NULL; >- int ret, saved_errno; >+ int saved_errno = 0; >+ int ret; > struct smb_filename *conv; > > if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, >@@ -1537,9 +1577,13 @@ static int shadow_copy2_ntimes(vfs_handle_struct *handle, > return -1; > } > ret = SMB_VFS_NEXT_NTIMES(handle, conv, ft); >- saved_errno = errno; >+ if (ret == -1) { >+ saved_errno = errno; >+ } > TALLOC_FREE(conv); >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return ret; > } > >@@ -1548,7 +1592,8 @@ static int shadow_copy2_readlink(vfs_handle_struct *handle, > { > time_t timestamp = 0; > char *stripped = NULL; >- int ret, saved_errno; >+ int saved_errno = 0; >+ int ret; > char *conv; > > if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, >@@ -1564,9 +1609,13 @@ static int shadow_copy2_readlink(vfs_handle_struct *handle, > return -1; > } > ret = SMB_VFS_NEXT_READLINK(handle, conv, buf, bufsiz); >- saved_errno = errno; >+ if (ret == -1) { >+ saved_errno = errno; >+ } > TALLOC_FREE(conv); >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return ret; > } > >@@ -1575,7 +1624,8 @@ static int shadow_copy2_mknod(vfs_handle_struct *handle, > { > time_t timestamp = 0; > char *stripped = NULL; >- int ret, saved_errno; >+ int saved_errno = 0; >+ int ret; > char *conv; > > if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, >@@ -1591,9 +1641,13 @@ static int shadow_copy2_mknod(vfs_handle_struct *handle, > return -1; > } > ret = SMB_VFS_NEXT_MKNOD(handle, conv, mode, dev); >- saved_errno = errno; >+ if (ret == -1) { >+ saved_errno = errno; >+ } > TALLOC_FREE(conv); >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return ret; > } > >@@ -1604,7 +1658,7 @@ static char *shadow_copy2_realpath(vfs_handle_struct *handle, > char *stripped = NULL; > char *tmp = NULL; > char *result = NULL; >- int saved_errno; >+ int saved_errno = 0; > > if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, > ×tamp, &stripped)) { >@@ -1622,10 +1676,14 @@ static char *shadow_copy2_realpath(vfs_handle_struct *handle, > result = SMB_VFS_NEXT_REALPATH(handle, tmp); > > done: >- saved_errno = errno; >+ if (result == NULL) { >+ saved_errno = errno; >+ } > TALLOC_FREE(tmp); > TALLOC_FREE(stripped); >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return result; > } > >@@ -2116,7 +2174,8 @@ static int shadow_copy2_mkdir(vfs_handle_struct *handle, > { > time_t timestamp = 0; > char *stripped = NULL; >- int ret, saved_errno; >+ int saved_errno = 0; >+ int ret; > char *conv; > struct smb_filename *conv_smb_fname = NULL; > >@@ -2145,10 +2204,14 @@ static int shadow_copy2_mkdir(vfs_handle_struct *handle, > return -1; > } > ret = SMB_VFS_NEXT_MKDIR(handle, conv_smb_fname, mode); >- saved_errno = errno; >+ if (ret == -1) { >+ saved_errno = errno; >+ } > TALLOC_FREE(conv); > TALLOC_FREE(conv_smb_fname); >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return ret; > } > >@@ -2157,7 +2220,8 @@ static int shadow_copy2_rmdir(vfs_handle_struct *handle, > { > time_t timestamp = 0; > char *stripped = NULL; >- int ret, saved_errno; >+ int saved_errno = 0; >+ int ret; > char *conv; > struct smb_filename *conv_smb_fname = NULL; > >@@ -2186,10 +2250,14 @@ static int shadow_copy2_rmdir(vfs_handle_struct *handle, > return -1; > } > ret = SMB_VFS_NEXT_RMDIR(handle, conv_smb_fname); >- saved_errno = errno; >+ if (ret == -1) { >+ saved_errno = errno; >+ } > TALLOC_FREE(conv_smb_fname); > TALLOC_FREE(conv); >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return ret; > } > >@@ -2198,7 +2266,8 @@ static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname, > { > time_t timestamp = 0; > char *stripped = NULL; >- int ret, saved_errno; >+ int saved_errno = 0; >+ int ret; > char *conv; > > if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, >@@ -2214,9 +2283,13 @@ static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname, > return -1; > } > ret = SMB_VFS_NEXT_CHFLAGS(handle, conv, flags); >- saved_errno = errno; >+ if (ret == -1) { >+ saved_errno = errno; >+ } > TALLOC_FREE(conv); >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return ret; > } > >@@ -2227,7 +2300,7 @@ static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle, > time_t timestamp = 0; > char *stripped = NULL; > ssize_t ret; >- int saved_errno; >+ int saved_errno = 0; > char *conv; > > if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, >@@ -2244,9 +2317,13 @@ static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle, > return -1; > } > ret = SMB_VFS_NEXT_GETXATTR(handle, conv, aname, value, size); >- saved_errno = errno; >+ if (ret == -1) { >+ saved_errno = errno; >+ } > TALLOC_FREE(conv); >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return ret; > } > >@@ -2257,7 +2334,7 @@ static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle, > time_t timestamp = 0; > char *stripped = NULL; > ssize_t ret; >- int saved_errno; >+ int saved_errno = 0; > char *conv; > > if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, >@@ -2273,9 +2350,13 @@ static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle, > return -1; > } > ret = SMB_VFS_NEXT_LISTXATTR(handle, conv, list, size); >- saved_errno = errno; >+ if (ret == -1) { >+ saved_errno = errno; >+ } > TALLOC_FREE(conv); >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return ret; > } > >@@ -2284,7 +2365,8 @@ static int shadow_copy2_removexattr(vfs_handle_struct *handle, > { > time_t timestamp = 0; > char *stripped = NULL; >- int ret, saved_errno; >+ int saved_errno = 0; >+ int ret; > char *conv; > > if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, >@@ -2300,9 +2382,13 @@ static int shadow_copy2_removexattr(vfs_handle_struct *handle, > return -1; > } > ret = SMB_VFS_NEXT_REMOVEXATTR(handle, conv, aname); >- saved_errno = errno; >+ if (ret == -1) { >+ saved_errno = errno; >+ } > TALLOC_FREE(conv); >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return ret; > } > >@@ -2314,7 +2400,7 @@ static int shadow_copy2_setxattr(struct vfs_handle_struct *handle, > time_t timestamp = 0; > char *stripped = NULL; > ssize_t ret; >- int saved_errno; >+ int saved_errno = 0; > char *conv; > > if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, >@@ -2331,9 +2417,13 @@ static int shadow_copy2_setxattr(struct vfs_handle_struct *handle, > return -1; > } > ret = SMB_VFS_NEXT_SETXATTR(handle, conv, aname, value, size, flags); >- saved_errno = errno; >+ if (ret == -1) { >+ saved_errno = errno; >+ } > TALLOC_FREE(conv); >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return ret; > } > >@@ -2344,7 +2434,7 @@ static int shadow_copy2_chmod_acl(vfs_handle_struct *handle, > time_t timestamp = 0; > char *stripped = NULL; > ssize_t ret; >- int saved_errno; >+ int saved_errno = 0; > char *conv = NULL; > struct smb_filename *conv_smb_fname = NULL; > >@@ -2374,10 +2464,14 @@ static int shadow_copy2_chmod_acl(vfs_handle_struct *handle, > return -1; > } > ret = SMB_VFS_NEXT_CHMOD_ACL(handle, conv_smb_fname, mode); >- saved_errno = errno; >+ if (ret == -1) { >+ saved_errno = errno; >+ } > TALLOC_FREE(conv); > TALLOC_FREE(conv_smb_fname); >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return ret; > } > >@@ -2390,7 +2484,7 @@ static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle, > time_t timestamp = 0; > char *stripped = NULL; > ssize_t ret; >- int saved_errno; >+ int saved_errno = 0; > char *conv; > > DEBUG(10, ("shadow_copy2_get_real_filename called for path=[%s], " >@@ -2417,9 +2511,13 @@ static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle, > ret = SMB_VFS_NEXT_GET_REAL_FILENAME(handle, conv, name, > mem_ctx, found_name); > DEBUG(10, ("NEXT_REAL_FILE_NAME returned %d\n", (int)ret)); >- saved_errno = errno; >+ if (ret == -1) { >+ saved_errno = errno; >+ } > TALLOC_FREE(conv); >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return ret; > } > >@@ -2431,7 +2529,7 @@ static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle, > char *tmp = NULL; > char *result = NULL; > char *parent_dir = NULL; >- int saved_errno; >+ int saved_errno = 0; > size_t rootpath_len = 0; > struct shadow_copy2_private *priv = NULL; > >@@ -2506,11 +2604,15 @@ static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle, > DBG_DEBUG("connect path is [%s]\n", result); > > done: >- saved_errno = errno; >+ if (result == NULL) { >+ saved_errno = errno; >+ } > TALLOC_FREE(tmp); > TALLOC_FREE(stripped); > TALLOC_FREE(parent_dir); >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > return result; > } > >@@ -2521,7 +2623,7 @@ static uint64_t shadow_copy2_disk_free(vfs_handle_struct *handle, > time_t timestamp = 0; > char *stripped = NULL; > ssize_t ret; >- int saved_errno; >+ int saved_errno = 0; > char *conv; > > if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path, >@@ -2541,9 +2643,13 @@ static uint64_t shadow_copy2_disk_free(vfs_handle_struct *handle, > > ret = SMB_VFS_NEXT_DISK_FREE(handle, conv, bsize, dfree, dsize); > >- saved_errno = errno; >+ if (ret == -1) { >+ saved_errno = errno; >+ } > TALLOC_FREE(conv); >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > > return ret; > } >@@ -2555,7 +2661,7 @@ static int shadow_copy2_get_quota(vfs_handle_struct *handle, const char *path, > time_t timestamp = 0; > char *stripped = NULL; > int ret; >- int saved_errno; >+ int saved_errno = 0; > char *conv; > > if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path, ×tamp, >@@ -2574,9 +2680,13 @@ static int shadow_copy2_get_quota(vfs_handle_struct *handle, const char *path, > > ret = SMB_VFS_NEXT_GET_QUOTA(handle, conv, qtype, id, dq); > >- saved_errno = errno; >+ if (ret == -1) { >+ saved_errno = errno; >+ } > TALLOC_FREE(conv); >- errno = saved_errno; >+ if (saved_errno != 0) { >+ errno = saved_errno; >+ } > > return ret; > } >-- >2.11.0.483.g087da7b7c-goog > > >From 290707cbf6e2fe9eb39ce0e0be6a45eb1b165b3f Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 26 Jan 2017 17:19:24 -0800 >Subject: [PATCH 20/20] s3: VFS: Don't allow symlink, link or rename on already > converted paths. > >Snapshot paths are a read-only filesystem. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > 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 f2a80f4b456..402eb70936b 100644 >--- a/source3/modules/vfs_shadow_copy2.c >+++ b/source3/modules/vfs_shadow_copy2.c >@@ -1109,15 +1109,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, >- ×tamp_src, NULL)) { >+ ×tamp_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, >- ×tamp_dst, NULL)) { >+ ×tamp_dst, NULL, &snappath_dst)) { > return -1; > } > if (timestamp_src != 0) { >@@ -1128,6 +1130,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); > } > >@@ -1136,19 +1149,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, >- ×tamp_old, NULL)) { >+ if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle, oldname, >+ ×tamp_old, NULL, &snappath_old)) { > return -1; > } >- if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname, >- ×tamp_new, NULL)) { >+ if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle, newname, >+ ×tamp_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); > } > >@@ -1157,19 +1179,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, >- ×tamp_old, NULL)) { >+ if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle, oldname, >+ ×tamp_old, NULL, &snappath_old)) { > return -1; > } >- if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname, >- ×tamp_new, NULL)) { >+ if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle, newname, >+ ×tamp_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.11.0.483.g087da7b7c-goog >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Flags:
uri
:
review+
jra
:
review?
(
obnox
)
Actions:
View
Attachments on
bug 12531
:
12844
|
12846
|
12849
|
12850
|
12851
|
12852
| 12860 |
12889
|
12890
|
12891
|
12904