From: Paulo Alcantara <p...@cjr.nz>

commit ff2c54a04097dee0b8899c485360719844d923f8 upstream.

Handle the case where a resolved target share is like
//server/users/dir, and the user "foo" has no read permission to
access the parent folder "users" but has access to the final path
component "dir".

is_path_remote() already implements that, so call it directly.

Signed-off-by: Paulo Alcantara (SUSE) <p...@cjr.nz>
Cc: sta...@vger.kernel.org # 5.11
Signed-off-by: Steve French <stfre...@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>
---
 fs/cifs/connect.c |   93 +++++++++++++++++++-----------------------------------
 1 file changed, 33 insertions(+), 60 deletions(-)

--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3280,73 +3280,46 @@ static void put_root_ses(struct cifs_ses
                cifs_put_smb_ses(ses);
 }
 
-/* Check if a path component is remote and then update @dfs_path accordingly */
-static int check_dfs_prepath(struct cifs_sb_info *cifs_sb, struct 
smb3_fs_context *ctx,
-                            const unsigned int xid, struct TCP_Server_Info 
*server,
-                            struct cifs_tcon *tcon, char **dfs_path)
+/* Set up next dfs prefix path in @dfs_path */
+static int next_dfs_prepath(struct cifs_sb_info *cifs_sb, struct 
smb3_fs_context *ctx,
+                           const unsigned int xid, struct TCP_Server_Info 
*server,
+                           struct cifs_tcon *tcon, char **dfs_path)
 {
-       char *path, *s;
-       char sep = CIFS_DIR_SEP(cifs_sb), tmp;
-       char *npath;
-       int rc = 0;
-       int added_treename = tcon->Flags & SMB_SHARE_IS_IN_DFS;
-       int skip = added_treename;
+       char *path, *npath;
+       int added_treename = is_tcon_dfs(tcon);
+       int rc;
 
        path = cifs_build_path_to_root(ctx, cifs_sb, tcon, added_treename);
        if (!path)
                return -ENOMEM;
 
-       /*
-        * Walk through the path components in @path and check if they're 
accessible. In case any of
-        * the components is -EREMOTE, then update @dfs_path with the next DFS 
referral request path
-        * (NOT including the remaining components).
-        */
-       s = path;
-       do {
-               /* skip separators */
-               while (*s && *s == sep)
-                       s++;
-               if (!*s)
-                       break;
-               /* next separator */
-               while (*s && *s != sep)
-                       s++;
-               /*
-                * if the treename is added, we then have to skip the first
-                * part within the separators
-                */
-               if (skip) {
-                       skip = 0;
-                       continue;
+       rc = is_path_remote(cifs_sb, ctx, xid, server, tcon);
+       if (rc == -EREMOTE) {
+               struct smb3_fs_context v = {NULL};
+               /* if @path contains a tree name, skip it in the prefix path */
+               if (added_treename) {
+                       rc = smb3_parse_devname(path, &v);
+                       if (rc)
+                               goto out;
+                       npath = build_unc_path_to_root(&v, cifs_sb, true);
+                       smb3_cleanup_fs_context_contents(&v);
+               } else {
+                       v.UNC = ctx->UNC;
+                       v.prepath = path + 1;
+                       npath = build_unc_path_to_root(&v, cifs_sb, true);
                }
-               tmp = *s;
-               *s = 0;
-               rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, path);
-               if (rc && rc == -EREMOTE) {
-                       struct smb3_fs_context v = {NULL};
-                       /* if @path contains a tree name, skip it in the prefix 
path */
-                       if (added_treename) {
-                               rc = smb3_parse_devname(path, &v);
-                               if (rc)
-                                       break;
-                               rc = -EREMOTE;
-                               npath = build_unc_path_to_root(&v, cifs_sb, 
true);
-                               smb3_cleanup_fs_context_contents(&v);
-                       } else {
-                               v.UNC = ctx->UNC;
-                               v.prepath = path + 1;
-                               npath = build_unc_path_to_root(&v, cifs_sb, 
true);
-                       }
-                       if (IS_ERR(npath)) {
-                               rc = PTR_ERR(npath);
-                               break;
-                       }
-                       kfree(*dfs_path);
-                       *dfs_path = npath;
+
+               if (IS_ERR(npath)) {
+                       rc = PTR_ERR(npath);
+                       goto out;
                }
-               *s = tmp;
-       } while (rc == 0);
 
+               kfree(*dfs_path);
+               *dfs_path = npath;
+               rc = -EREMOTE;
+       }
+
+out:
        kfree(path);
        return rc;
 }
@@ -3432,8 +3405,8 @@ int cifs_mount(struct cifs_sb_info *cifs
                        put_root_ses(root_ses);
                        set_root_ses(cifs_sb, ses, &root_ses);
                }
-               /* Check for remaining path components and then continue 
chasing them (-EREMOTE) */
-               rc = check_dfs_prepath(cifs_sb, ctx, xid, server, tcon, 
&ref_path);
+               /* Get next dfs path and then continue chasing them if -EREMOTE 
*/
+               rc = next_dfs_prepath(cifs_sb, ctx, xid, server, tcon, 
&ref_path);
                /* Prevent recursion on broken link referrals */
                if (rc == -EREMOTE && ++count > MAX_NESTED_LINKS)
                        rc = -ELOOP;


Reply via email to