Skip to content

Commit 0d4873f

Browse files
Ronnie Sahlbergsmfrench
authored andcommitted
cifs: fix dfs domain referrals
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 <lsahlber@redhat.com> Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent bd2f0b4 commit 0d4873f

6 files changed

Lines changed: 75 additions & 16 deletions

File tree

fs/cifs/cifs_dfs_ref.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,9 @@ cifs_build_devname(char *nodename, const char *prepath)
133133
* Caller is responsible for freeing returned value if it is not error.
134134
*/
135135
char *cifs_compose_mount_options(const char *sb_mountdata,
136-
const char *fullpath,
137-
const struct dfs_info3_param *ref)
136+
const char *fullpath,
137+
const struct dfs_info3_param *ref,
138+
char **devname)
138139
{
139140
int rc;
140141
char *name;
@@ -231,7 +232,10 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
231232
strcat(mountdata, "ip=");
232233
strcat(mountdata, srvIP);
233234

234-
kfree(name);
235+
if (devname)
236+
*devname = name;
237+
else
238+
kfree(name);
235239

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

279283
/* strip first '\' from fullpath */
280284
mountdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options,
281-
fullpath + 1, NULL);
285+
fullpath + 1, NULL, NULL);
282286
if (IS_ERR(mountdata)) {
283287
kfree(devname);
284288
return (struct vfsmount *)mountdata;

fs/cifs/cifsfs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -822,7 +822,7 @@ cifs_smb3_do_mount(struct file_system_type *fs_type,
822822
goto out;
823823
}
824824

825-
rc = cifs_setup_volume_info(cifs_sb->ctx);
825+
rc = cifs_setup_volume_info(cifs_sb->ctx, NULL, old_ctx->UNC);
826826
if (rc) {
827827
root = ERR_PTR(rc);
828828
goto out;

fs/cifs/cifsproto.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ extern char *cifs_build_path_to_root(struct smb3_fs_context *ctx,
7878
int add_treename);
7979
extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
8080
extern char *cifs_compose_mount_options(const char *sb_mountdata,
81-
const char *fullpath, const struct dfs_info3_param *ref);
81+
const char *fullpath, const struct dfs_info3_param *ref,
82+
char **devname);
8283
/* extern void renew_parental_timestamps(struct dentry *direntry);*/
8384
extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
8485
struct TCP_Server_Info *server);
@@ -89,6 +90,7 @@ extern void cifs_wake_up_task(struct mid_q_entry *mid);
8990
extern int cifs_handle_standard(struct TCP_Server_Info *server,
9091
struct mid_q_entry *mid);
9192
extern int smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx);
93+
extern int smb3_parse_opt(const char *options, const char *key, char **val);
9294
extern bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs);
9395
extern int cifs_discard_remaining_data(struct TCP_Server_Info *server);
9496
extern int cifs_call_async(struct TCP_Server_Info *server,
@@ -549,7 +551,7 @@ extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8,
549551
unsigned char *p24);
550552

551553
extern int
552-
cifs_setup_volume_info(struct smb3_fs_context *ctx);
554+
cifs_setup_volume_info(struct smb3_fs_context *ctx, const char *mntopts, const char *devname);
553555

554556
extern struct TCP_Server_Info *
555557
cifs_find_tcp_session(struct smb3_fs_context *ctx);

fs/cifs/connect.c

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2972,17 +2972,20 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses,
29722972
rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb),
29732973
ref_path, &referral, NULL);
29742974
if (!rc) {
2975+
char *fake_devname = NULL;
2976+
29752977
mdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options,
2976-
full_path + 1, &referral);
2978+
full_path + 1, &referral,
2979+
&fake_devname);
29772980
free_dfs_info_param(&referral);
29782981

29792982
if (IS_ERR(mdata)) {
29802983
rc = PTR_ERR(mdata);
29812984
mdata = NULL;
29822985
} else {
2983-
smb3_cleanup_fs_context_contents(ctx);
2984-
rc = cifs_setup_volume_info(ctx);
2986+
rc = cifs_setup_volume_info(ctx, mdata, fake_devname);
29852987
}
2988+
kfree(fake_devname);
29862989
kfree(cifs_sb->ctx->mount_options);
29872990
cifs_sb->ctx->mount_options = mdata;
29882991
}
@@ -3036,6 +3039,7 @@ static int setup_dfs_tgt_conn(const char *path, const char *full_path,
30363039
struct dfs_info3_param ref = {0};
30373040
char *mdata = NULL;
30383041
struct smb3_fs_context fake_ctx = {NULL};
3042+
char *fake_devname = NULL;
30393043

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

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

30463050
mdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options,
3047-
full_path + 1, &ref);
3051+
full_path + 1, &ref,
3052+
&fake_devname);
30483053
free_dfs_info_param(&ref);
30493054

30503055
if (IS_ERR(mdata)) {
30513056
rc = PTR_ERR(mdata);
30523057
mdata = NULL;
30533058
} else
3054-
rc = cifs_setup_volume_info(&fake_ctx);
3059+
rc = cifs_setup_volume_info(&fake_ctx, mdata, fake_devname);
30553060

30563061
kfree(mdata);
3062+
kfree(fake_devname);
30573063

30583064
if (!rc) {
30593065
/*
@@ -3122,10 +3128,24 @@ static int do_dfs_failover(const char *path, const char *full_path, struct cifs_
31223128
* we should pass a clone of the original context?
31233129
*/
31243130
int
3125-
cifs_setup_volume_info(struct smb3_fs_context *ctx)
3131+
cifs_setup_volume_info(struct smb3_fs_context *ctx, const char *mntopts, const char *devname)
31263132
{
31273133
int rc = 0;
31283134

3135+
smb3_parse_devname(devname, ctx);
3136+
3137+
if (mntopts) {
3138+
char *ip;
3139+
3140+
cifs_dbg(FYI, "%s: mntopts=%s\n", __func__, mntopts);
3141+
rc = smb3_parse_opt(mntopts, "ip", &ip);
3142+
if (!rc && !cifs_convert_address((struct sockaddr *)&ctx->dstaddr, ip,
3143+
strlen(ip))) {
3144+
cifs_dbg(VFS, "%s: failed to convert ip address\n", __func__);
3145+
return -EINVAL;
3146+
}
3147+
}
3148+
31293149
if (ctx->nullauth) {
31303150
cifs_dbg(FYI, "Anonymous login\n");
31313151
kfree(ctx->username);

fs/cifs/dfs_cache.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,7 +1417,7 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi,
14171417
int rc;
14181418
struct cache_entry *ce;
14191419
struct dfs_info3_param ref = {0};
1420-
char *mdata = NULL;
1420+
char *mdata = NULL, *devname = NULL;
14211421
struct TCP_Server_Info *server;
14221422
struct cifs_ses *ses;
14231423
struct smb3_fs_context ctx = {NULL};
@@ -1444,7 +1444,8 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi,
14441444

14451445
up_read(&htable_rw_lock);
14461446

1447-
mdata = cifs_compose_mount_options(vi->mntdata, rpath, &ref);
1447+
mdata = cifs_compose_mount_options(vi->mntdata, rpath, &ref,
1448+
&devname);
14481449
free_dfs_info_param(&ref);
14491450

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

1456-
rc = cifs_setup_volume_info(&ctx);
1457+
rc = cifs_setup_volume_info(&ctx, NULL, devname);
14571458

14581459
if (rc) {
14591460
ses = ERR_PTR(rc);
@@ -1472,6 +1473,7 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi,
14721473
smb3_cleanup_fs_context_contents(&ctx);
14731474
kfree(mdata);
14741475
kfree(rpath);
1476+
kfree(devname);
14751477

14761478
return ses;
14771479
}

fs/cifs/fs_context.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,37 @@ cifs_parse_smb_version(char *value, struct smb3_fs_context *ctx, bool is_smb3)
401401
return 0;
402402
}
403403

404+
int smb3_parse_opt(const char *options, const char *key, char **val)
405+
{
406+
int rc = -ENOENT;
407+
char *opts, *orig, *p;
408+
409+
orig = opts = kstrdup(options, GFP_KERNEL);
410+
if (!opts)
411+
return -ENOMEM;
412+
413+
while ((p = strsep(&opts, ","))) {
414+
char *nval;
415+
416+
if (!*p)
417+
continue;
418+
if (strncasecmp(p, key, strlen(key)))
419+
continue;
420+
nval = strchr(p, '=');
421+
if (nval) {
422+
if (nval == p)
423+
continue;
424+
*nval++ = 0;
425+
*val = kstrndup(nval, strlen(nval), GFP_KERNEL);
426+
rc = !*val ? -ENOMEM : 0;
427+
goto out;
428+
}
429+
}
430+
out:
431+
kfree(orig);
432+
return rc;
433+
}
434+
404435
/*
405436
* Parse a devname into substrings and populate the ctx->UNC and ctx->prepath
406437
* fields with the result. Returns 0 on success and an error otherwise

0 commit comments

Comments
 (0)