cifs: check all path components in resolved dfs target
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) <pc@cjr.nz> Cc: stable@vger.kernel.org # 5.11 Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
8513222b9e
commit
ff2c54a040
|
@ -3289,73 +3289,46 @@ static void put_root_ses(struct cifs_ses *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;
|
||||
}
|
||||
*s = tmp;
|
||||
} while (rc == 0);
|
||||
|
||||
if (IS_ERR(npath)) {
|
||||
rc = PTR_ERR(npath);
|
||||
goto out;
|
||||
}
|
||||
|
||||
kfree(*dfs_path);
|
||||
*dfs_path = npath;
|
||||
rc = -EREMOTE;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(path);
|
||||
return rc;
|
||||
}
|
||||
|
@ -3441,8 +3414,8 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
|
|||
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;
|
||||
|
|
Loading…
Reference in New Issue