From ecdbe6e7b9bf25fd9a6813a3247386eb1eff2582 Mon Sep 17 00:00:00 2001 From: Daniel Kobras Date: Fri, 23 Jun 2017 15:39:21 +0200 Subject: [PATCH] s3: smbd: fix regression with non-wide symlinks to directories over SMB3. The errno returned by open() is ambiguous when called with flags O_NOFOLLOW and O_DIRECTORY on a symlink. With ELOOP, we know for certain that we've tried to open a symlink. With ENOTDIR, we might have hit a symlink, and need to perform further checks to be sure. Adjust non_widelink_open() accordingly. This fixes a regression where symlinks to directories within the same share were no longer followed for some call paths on systems returning ENOTDIR in the above case. Also remove the knownfail added in previous commit. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12860 Signed-off-by: Daniel Kobras Reviewed-by: Jeremy Allison Reviewed-by: Ralph Boehme (cherry picked from commit acc16592b451905dabc093f1d261e93cd3b59520) --- selftest/knownfail | 1 - source3/smbd/open.c | 24 ++++++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/selftest/knownfail b/selftest/knownfail index 84e2640fa19..17667cd29d0 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -290,4 +290,3 @@ ^samba4.drs.ridalloc_exop.python.*ridalloc_exop.DrsReplicaSyncTestCase.test_join_time_ridalloc ^samba4.drs.ridalloc_exop.python.*ridalloc_exop.DrsReplicaSyncTestCase.test_rid_set_dbcheck_after_seize ^samba4.drs.ridalloc_exop.python.*ridalloc_exop.DrsReplicaSyncTestCase.test_rid_set_dbcheck -+^samba3.blackbox.smbclient_s3.*follow local symlinks.* diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 3368bae6ea2..c96bc9ba98d 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -579,7 +579,18 @@ static int non_widelink_open(struct connection_struct *conn, if (fd == -1) { saved_errno = link_errno_convert(errno); - if (saved_errno == ELOOP) { + /* + * Trying to open a symlink to a directory with O_NOFOLLOW and + * O_DIRECTORY can return either of ELOOP and ENOTDIR. So + * ENOTDIR really means: might be a symlink, but we're not sure. + * In this case, we just assume there's a symlink. If we were + * wrong, process_symlink_open() will return EINVAL. We check + * this below, and fall back to returning the initial + * saved_errno. + * + * BUG: https://bugzilla.samba.org/show_bug.cgi?id=12860 + */ + if (saved_errno == ELOOP || saved_errno == ENOTDIR) { if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) { /* Never follow symlinks on posix open. */ goto out; @@ -589,7 +600,7 @@ static int non_widelink_open(struct connection_struct *conn, goto out; } /* - * We have a symlink. Follow in userspace + * We may have a symlink. Follow in userspace * to ensure it's under the share definition. */ fd = process_symlink_open(conn, @@ -600,6 +611,15 @@ static int non_widelink_open(struct connection_struct *conn, mode, link_depth); if (fd == -1) { + if (saved_errno == ENOTDIR && + errno == EINVAL) { + /* + * O_DIRECTORY on neither a directory, + * nor a symlink. Just return + * saved_errno from initial open() + */ + goto out; + } saved_errno = link_errno_convert(errno); } -- 2.47.2