From 47e44f311f1b8fa2763c0dc9e2a5635514faf69d Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 7 Jul 2017 12:57:57 +0200 Subject: [PATCH] s3/smbd: let non_widelink_open() chdir() to directories directly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the caller passes O_DIRECTORY we just try to chdir() to smb_fname directly, not to the parent directory. The security check in check_reduced_name() will continue to work, but this fixes the case of an open() for a previous version of a subdirectory that contains snapshopt. Eg: [share] path = /shares/test vfs objects = shadow_copy2 shadow:snapdir = .snapshots shadow:snapdirseverywhere = yes Directory tree with fake snapshots: $ tree -a /shares/test/ /shares/test/ ├── dir │   ├── file │   └── .snapshots │   └── @GMT-2017.07.04-04.30.12 │   └── file ├── dir2 │   └── file ├── file ├── .snapshots │   └── @GMT-2001.01.01-00.00.00 │   ├── dir2 │   │   └── file │   └── file └── testfsctl.dat ./bin/smbclient -U slow%x //localhost/share -c 'ls @GMT-2017.07.04-04.30.12/dir/*' NT_STATUS_OBJECT_NAME_NOT_FOUND listing \@GMT-2017.07.04-04.30.12\dir\* Bug: https://bugzilla.samba.org/show_bug.cgi?id=12885 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit b886a9443d49f6e27fa3863d87c9e24d12e62874) --- source3/smbd/open.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/source3/smbd/open.c b/source3/smbd/open.c index f19af87..5efb6f5 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -527,12 +527,32 @@ static int non_widelink_open(struct connection_struct *conn, char *oldwd = NULL; char *parent_dir = NULL; const char *final_component = NULL; + bool is_directory = false; + bool ok; - if (!parent_dirname(talloc_tos(), - smb_fname->base_name, - &parent_dir, - &final_component)) { - goto out; +#ifdef O_DIRECTORY + if (flags & O_DIRECTORY) { + is_directory = true; + } +#endif + + if (is_directory) { + parent_dir = talloc_strdup(talloc_tos(), smb_fname->base_name); + if (parent_dir == NULL) { + saved_errno = errno; + goto out; + } + + final_component = "."; + } else { + ok = parent_dirname(talloc_tos(), + smb_fname->base_name, + &parent_dir, + &final_component); + if (!ok) { + saved_errno = errno; + goto out; + } } oldwd = vfs_GetWd(talloc_tos(), conn); -- 2.9.4