From: Ralph Boehme Date: Tue, 5 May 2020 08:13:00 +0000 (+0200) Subject: vfs_shadow_copy2: implement case canonicalisation in shadow_copy2_get_real_filename() X-Git-Tag: ldb-2.2.0~639 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a3d1ac2a597e2441d6855db566306298ae5db99b;p=thirdparty%2Fsamba.git 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 Reviewed-by: Jeremy Allison --- 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 543bee3921a..f8f0f82e79e 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -2411,6 +2411,8 @@ static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle, char **found_name) { char *path = fname->base_name; + struct shadow_copy2_private *priv = NULL; + struct shadow_copy2_config *config = NULL; time_t timestamp = 0; char *stripped = NULL; ssize_t ret; @@ -2418,8 +2420,11 @@ static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle, char *conv; struct smb_filename conv_fname; - DEBUG(10, ("shadow_copy2_get_real_filename called for path=[%s], " - "name=[%s]\n", path, name)); + SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private, + return -1); + config = priv->config; + + DBG_DEBUG("Path=[%s] name=[%s]\n", smb_fname_str_dbg(fname), name); if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, ×tamp, &stripped)) { @@ -2431,11 +2436,37 @@ static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle, return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, fname, name, mem_ctx, found_name); } + + /* + * Note that stripped may be an empty string "" if path was ".". 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; + } } conv_fname = (struct smb_filename) { @@ -2447,14 +2478,34 @@ static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle, ret = SMB_VFS_NEXT_GET_REAL_FILENAME(handle, &conv_fname, 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,