From 84362eef4cfd199e0ef3e019f6ed444d1a73ed0d Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 23 Apr 2020 16:10:23 +0200 Subject: [PATCH] vfs_shadow_copy2: implement case canonicalisation in shadow_copy2_get_real_filename() unix_convert() can't do this for us in snapdirseverywhere mode, so we do it ourselves. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14350 Signed-off-by: Ralph Boehme (Similar to commit a3d1ac2a597e2441d6855db566306298ae5db99b) Autobuild-User(v4-11-test): Karolin Seeger Autobuild-Date(v4-11-test): Wed May 13 14:44:57 UTC 2020 on sn-devel-184 --- .../knownfail.d/samba3.blackbox.shadow_copy2 | 4 - source3/modules/vfs_shadow_copy2.c | 91 +++++++++++++++++-- 2 files changed, 83 insertions(+), 12 deletions(-) delete mode 100644 selftest/knownfail.d/samba3.blackbox.shadow_copy2 diff --git a/selftest/knownfail.d/samba3.blackbox.shadow_copy2 b/selftest/knownfail.d/samba3.blackbox.shadow_copy2 deleted file mode 100644 index f869dc899ab..00000000000 --- a/selftest/knownfail.d/samba3.blackbox.shadow_copy2 +++ /dev/null @@ -1,4 +0,0 @@ -^samba3.blackbox.shadow_copy2.NT1.fetch a previous version of a regular file via non-canonical parent path\(fileserver_smb1_done\)$ -^samba3.blackbox.shadow_copy2.SMB3.fetch a previous version of a regular file via non-canonical parent path\(fileserver\)$ -^samba3.blackbox.shadow_copy2.NT1.fetch a previous version of a regular file via non-canonical path\(fileserver_smb1_done\)$ -^samba3.blackbox.shadow_copy2.SMB3.fetch a previous version of a regular file via non-canonical path\(fileserver\)$ diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index e5def9669f4..056fa9e80cc 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -852,6 +852,11 @@ static char *shadow_copy2_do_convert(TALLOC_CTX *mem_ctx, config = priv->config; + /* + * Note that stripped may be an empty string "" if the outer level VFS + * function got passed a single @GMT-only token path. + */ + DEBUG(10, ("converting '%s'\n", name)); if (!config->snapdirseverywhere) { @@ -2707,15 +2712,35 @@ static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, char **found_name) { + struct shadow_copy2_private *priv = NULL; + struct shadow_copy2_config *config = NULL; + bool name_is_gmt_token = is_gmt_token(name); time_t timestamp = 0; char *stripped = NULL; ssize_t ret; int saved_errno = 0; char *conv; + SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private, + return -1); + config = priv->config; + DEBUG(10, ("shadow_copy2_get_real_filename called for path=[%s], " "name=[%s]\n", path, name)); + if (ISDOT(path) && name_is_gmt_token) { + /* + * This happens in the first round of looping over the path in + * unix_convert(). Eg for a snapshot path "@GMT-.../foo/bar" we + * would be called with path="." and name="@GMT-...". + */ + *found_name = talloc_strdup(mem_ctx, name); + if (*found_name == NULL) { + return -1; + } + return 0; + } + if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path, ×tamp, &stripped)) { DEBUG(10, ("shadow_copy2_strip_snapshot failed\n")); @@ -2726,25 +2751,75 @@ static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle, return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name, mem_ctx, found_name); } + + /* + * Note that stripped may be an empty string "" if path was a single + * @GMT-only token. As shadow_copy2_convert() combines "" with the + * shadow-copy tree connect root fullpath and + * get_real_filename_full_scan() has an explicit check for "" this + * works. + */ + DBG_DEBUG("stripped [%s]\n", stripped); + conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp); - TALLOC_FREE(stripped); if (conv == NULL) { - DEBUG(10, ("shadow_copy2_convert failed\n")); - return -1; + if (!config->snapdirseverywhere) { + DBG_DEBUG("shadow_copy2_convert [%s] failed\n", stripped); + return -1; + } + + /* + * We're called in the path traversal loop in unix_convert() + * walking down the directory hierarchy. shadow_copy2_convert() + * will fail if the snapshot directory is futher down in the + * hierachy. Set conv to the original stripped path and try to + * look it up in the filesystem with + * SMB_VFS_NEXT_GET_REAL_FILENAME() or + * get_real_filename_full_scan(). + */ + DBG_DEBUG("Use stripped [%s] as conv\n", stripped); + conv = talloc_strdup(talloc_tos(), stripped); + if (conv == NULL) { + TALLOC_FREE(stripped); + return -1; + } } + TALLOC_FREE(stripped); + DEBUG(10, ("Calling NEXT_GET_REAL_FILE_NAME for conv=[%s], " "name=[%s]\n", conv, name)); + 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)); - if (ret == -1) { - saved_errno = errno; + if (ret == 0) { + return 0; } - TALLOC_FREE(conv); - if (saved_errno != 0) { + if (errno != EOPNOTSUPP) { + TALLOC_FREE(conv); + errno = EOPNOTSUPP; + return -1; + } + + ret = get_real_filename_full_scan(handle->conn, + conv, + name, + false, + mem_ctx, + found_name); + if (ret != 0) { + saved_errno = errno; + DBG_DEBUG("Scan [%s] for [%s] failed\n", + conv, name); errno = saved_errno; + return -1; } - return ret; + + DBG_DEBUG("Scan [%s] for [%s] returned [%s]\n", + conv, name, *found_name); + + TALLOC_FREE(conv); + return 0; } static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle, -- 2.47.2