Skip to content

Commit

Permalink
cifs: fix dfs domain referrals
Browse files Browse the repository at this point in the history
The new mount API requires additional changes to how DFS
is handled. Additional testing of DFS uncovered problems
with domain based DFS referrals (a follow on patch addresses
DFS links) which this patch addresses.

Signed-off-by: Ronnie Sahlberg <[email protected]>
Signed-off-by: Paulo Alcantara (SUSE) <[email protected]>
Signed-off-by: Steve French <[email protected]>
  • Loading branch information
Ronnie Sahlberg authored and Steve French committed Jan 29, 2021
1 parent bd2f0b4 commit 0d4873f
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 16 deletions.
12 changes: 8 additions & 4 deletions fs/cifs/cifs_dfs_ref.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,9 @@ cifs_build_devname(char *nodename, const char *prepath)
* Caller is responsible for freeing returned value if it is not error.
*/
char *cifs_compose_mount_options(const char *sb_mountdata,
const char *fullpath,
const struct dfs_info3_param *ref)
const char *fullpath,
const struct dfs_info3_param *ref,
char **devname)
{
int rc;
char *name;
Expand Down Expand Up @@ -231,7 +232,10 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
strcat(mountdata, "ip=");
strcat(mountdata, srvIP);

kfree(name);
if (devname)
*devname = name;
else
kfree(name);

/*cifs_dbg(FYI, "%s: parent mountdata: %s\n", __func__, sb_mountdata);*/
/*cifs_dbg(FYI, "%s: submount mountdata: %s\n", __func__, mountdata );*/
Expand Down Expand Up @@ -278,7 +282,7 @@ static struct vfsmount *cifs_dfs_do_mount(struct dentry *mntpt,

/* strip first '\' from fullpath */
mountdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options,
fullpath + 1, NULL);
fullpath + 1, NULL, NULL);
if (IS_ERR(mountdata)) {
kfree(devname);
return (struct vfsmount *)mountdata;
Expand Down
2 changes: 1 addition & 1 deletion fs/cifs/cifsfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -822,7 +822,7 @@ cifs_smb3_do_mount(struct file_system_type *fs_type,
goto out;
}

rc = cifs_setup_volume_info(cifs_sb->ctx);
rc = cifs_setup_volume_info(cifs_sb->ctx, NULL, old_ctx->UNC);
if (rc) {
root = ERR_PTR(rc);
goto out;
Expand Down
6 changes: 4 additions & 2 deletions fs/cifs/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ extern char *cifs_build_path_to_root(struct smb3_fs_context *ctx,
int add_treename);
extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
extern char *cifs_compose_mount_options(const char *sb_mountdata,
const char *fullpath, const struct dfs_info3_param *ref);
const char *fullpath, const struct dfs_info3_param *ref,
char **devname);
/* extern void renew_parental_timestamps(struct dentry *direntry);*/
extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
struct TCP_Server_Info *server);
Expand All @@ -89,6 +90,7 @@ extern void cifs_wake_up_task(struct mid_q_entry *mid);
extern int cifs_handle_standard(struct TCP_Server_Info *server,
struct mid_q_entry *mid);
extern int smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx);
extern int smb3_parse_opt(const char *options, const char *key, char **val);
extern bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs);
extern int cifs_discard_remaining_data(struct TCP_Server_Info *server);
extern int cifs_call_async(struct TCP_Server_Info *server,
Expand Down Expand Up @@ -549,7 +551,7 @@ extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8,
unsigned char *p24);

extern int
cifs_setup_volume_info(struct smb3_fs_context *ctx);
cifs_setup_volume_info(struct smb3_fs_context *ctx, const char *mntopts, const char *devname);

extern struct TCP_Server_Info *
cifs_find_tcp_session(struct smb3_fs_context *ctx);
Expand Down
32 changes: 26 additions & 6 deletions fs/cifs/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -2972,17 +2972,20 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses,
rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb),
ref_path, &referral, NULL);
if (!rc) {
char *fake_devname = NULL;

mdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options,
full_path + 1, &referral);
full_path + 1, &referral,
&fake_devname);
free_dfs_info_param(&referral);

if (IS_ERR(mdata)) {
rc = PTR_ERR(mdata);
mdata = NULL;
} else {
smb3_cleanup_fs_context_contents(ctx);
rc = cifs_setup_volume_info(ctx);
rc = cifs_setup_volume_info(ctx, mdata, fake_devname);
}
kfree(fake_devname);
kfree(cifs_sb->ctx->mount_options);
cifs_sb->ctx->mount_options = mdata;
}
Expand Down Expand Up @@ -3036,6 +3039,7 @@ static int setup_dfs_tgt_conn(const char *path, const char *full_path,
struct dfs_info3_param ref = {0};
char *mdata = NULL;
struct smb3_fs_context fake_ctx = {NULL};
char *fake_devname = NULL;

cifs_dbg(FYI, "%s: dfs path: %s\n", __func__, path);

Expand All @@ -3044,16 +3048,18 @@ static int setup_dfs_tgt_conn(const char *path, const char *full_path,
return rc;

mdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options,
full_path + 1, &ref);
full_path + 1, &ref,
&fake_devname);
free_dfs_info_param(&ref);

if (IS_ERR(mdata)) {
rc = PTR_ERR(mdata);
mdata = NULL;
} else
rc = cifs_setup_volume_info(&fake_ctx);
rc = cifs_setup_volume_info(&fake_ctx, mdata, fake_devname);

kfree(mdata);
kfree(fake_devname);

if (!rc) {
/*
Expand Down Expand Up @@ -3122,10 +3128,24 @@ static int do_dfs_failover(const char *path, const char *full_path, struct cifs_
* we should pass a clone of the original context?
*/
int
cifs_setup_volume_info(struct smb3_fs_context *ctx)
cifs_setup_volume_info(struct smb3_fs_context *ctx, const char *mntopts, const char *devname)
{
int rc = 0;

smb3_parse_devname(devname, ctx);

if (mntopts) {
char *ip;

cifs_dbg(FYI, "%s: mntopts=%s\n", __func__, mntopts);
rc = smb3_parse_opt(mntopts, "ip", &ip);
if (!rc && !cifs_convert_address((struct sockaddr *)&ctx->dstaddr, ip,
strlen(ip))) {
cifs_dbg(VFS, "%s: failed to convert ip address\n", __func__);
return -EINVAL;
}
}

if (ctx->nullauth) {
cifs_dbg(FYI, "Anonymous login\n");
kfree(ctx->username);
Expand Down
8 changes: 5 additions & 3 deletions fs/cifs/dfs_cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -1417,7 +1417,7 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi,
int rc;
struct cache_entry *ce;
struct dfs_info3_param ref = {0};
char *mdata = NULL;
char *mdata = NULL, *devname = NULL;
struct TCP_Server_Info *server;
struct cifs_ses *ses;
struct smb3_fs_context ctx = {NULL};
Expand All @@ -1444,7 +1444,8 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi,

up_read(&htable_rw_lock);

mdata = cifs_compose_mount_options(vi->mntdata, rpath, &ref);
mdata = cifs_compose_mount_options(vi->mntdata, rpath, &ref,
&devname);
free_dfs_info_param(&ref);

if (IS_ERR(mdata)) {
Expand All @@ -1453,7 +1454,7 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi,
goto out;
}

rc = cifs_setup_volume_info(&ctx);
rc = cifs_setup_volume_info(&ctx, NULL, devname);

if (rc) {
ses = ERR_PTR(rc);
Expand All @@ -1472,6 +1473,7 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi,
smb3_cleanup_fs_context_contents(&ctx);
kfree(mdata);
kfree(rpath);
kfree(devname);

return ses;
}
Expand Down
31 changes: 31 additions & 0 deletions fs/cifs/fs_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,37 @@ cifs_parse_smb_version(char *value, struct smb3_fs_context *ctx, bool is_smb3)
return 0;
}

int smb3_parse_opt(const char *options, const char *key, char **val)
{
int rc = -ENOENT;
char *opts, *orig, *p;

orig = opts = kstrdup(options, GFP_KERNEL);
if (!opts)
return -ENOMEM;

while ((p = strsep(&opts, ","))) {
char *nval;

if (!*p)
continue;
if (strncasecmp(p, key, strlen(key)))
continue;
nval = strchr(p, '=');
if (nval) {
if (nval == p)
continue;
*nval++ = 0;
*val = kstrndup(nval, strlen(nval), GFP_KERNEL);
rc = !*val ? -ENOMEM : 0;
goto out;
}
}
out:
kfree(orig);
return rc;
}

/*
* Parse a devname into substrings and populate the ctx->UNC and ctx->prepath
* fields with the result. Returns 0 on success and an error otherwise
Expand Down

0 comments on commit 0d4873f

Please sign in to comment.