[CIFS] make sure that DFS pathnames are properly formed
The paths in a DFS request are supposed to only have a single preceding backslash, but we are sending them with a double backslash. This is exposing a bug in Windows where it also sends a path in the response that has a double backslash. The existing code that builds the mount option string however expects a double backslash prefix in a couple of places when it tries to use the path returned by build_path_from_dentry. Fix compose_mount_options to expect properly formed DFS paths (single backslash at front). Also clean up error handling in that function. There was a possible NULL pointer dereference and situations where a partially built option string would be returned. Tested against Samba 3.0.28-ish server and Samba 3.3 and Win2k8. CC: Stable <stable@kernel.org> Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
parent
ac6a3ef405
commit
c6fbba0546
@ -4,7 +4,8 @@ Add "forcemandatorylock" mount option to allow user to use mandatory
|
|||||||
rather than posix (advisory) byte range locks, even though server would
|
rather than posix (advisory) byte range locks, even though server would
|
||||||
support posix byte range locks. Fix query of root inode when prefixpath
|
support posix byte range locks. Fix query of root inode when prefixpath
|
||||||
specified and user does not have access to query information about the
|
specified and user does not have access to query information about the
|
||||||
top of the share.
|
top of the share. Fix problem in 2.6.28 resolving DFS paths to
|
||||||
|
Samba servers (worked to Windows).
|
||||||
|
|
||||||
Version 1.55
|
Version 1.55
|
||||||
------------
|
------------
|
||||||
|
@ -122,7 +122,7 @@ static char *compose_mount_options(const char *sb_mountdata,
|
|||||||
char **devname)
|
char **devname)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
char *mountdata;
|
char *mountdata = NULL;
|
||||||
int md_len;
|
int md_len;
|
||||||
char *tkn_e;
|
char *tkn_e;
|
||||||
char *srvIP = NULL;
|
char *srvIP = NULL;
|
||||||
@ -136,10 +136,9 @@ static char *compose_mount_options(const char *sb_mountdata,
|
|||||||
*devname = cifs_get_share_name(ref->node_name);
|
*devname = cifs_get_share_name(ref->node_name);
|
||||||
rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
|
rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
cERROR(1, ("%s: Failed to resolve server part of %s to IP",
|
cERROR(1, ("%s: Failed to resolve server part of %s to IP: %d",
|
||||||
__func__, *devname));
|
__func__, *devname, rc));;
|
||||||
mountdata = ERR_PTR(rc);
|
goto compose_mount_options_err;
|
||||||
goto compose_mount_options_out;
|
|
||||||
}
|
}
|
||||||
/* md_len = strlen(...) + 12 for 'sep+prefixpath='
|
/* md_len = strlen(...) + 12 for 'sep+prefixpath='
|
||||||
* assuming that we have 'unc=' and 'ip=' in
|
* assuming that we have 'unc=' and 'ip=' in
|
||||||
@ -149,8 +148,8 @@ static char *compose_mount_options(const char *sb_mountdata,
|
|||||||
strlen(ref->node_name) + 12;
|
strlen(ref->node_name) + 12;
|
||||||
mountdata = kzalloc(md_len+1, GFP_KERNEL);
|
mountdata = kzalloc(md_len+1, GFP_KERNEL);
|
||||||
if (mountdata == NULL) {
|
if (mountdata == NULL) {
|
||||||
mountdata = ERR_PTR(-ENOMEM);
|
rc = -ENOMEM;
|
||||||
goto compose_mount_options_out;
|
goto compose_mount_options_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy all options except of unc,ip,prefixpath */
|
/* copy all options except of unc,ip,prefixpath */
|
||||||
@ -197,18 +196,32 @@ static char *compose_mount_options(const char *sb_mountdata,
|
|||||||
|
|
||||||
/* find & copy prefixpath */
|
/* find & copy prefixpath */
|
||||||
tkn_e = strchr(ref->node_name + 2, '\\');
|
tkn_e = strchr(ref->node_name + 2, '\\');
|
||||||
if (tkn_e == NULL) /* invalid unc, missing share name*/
|
if (tkn_e == NULL) {
|
||||||
goto compose_mount_options_out;
|
/* invalid unc, missing share name*/
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto compose_mount_options_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this function gives us a path with a double backslash prefix. We
|
||||||
|
* require a single backslash for DFS. Temporarily increment fullpath
|
||||||
|
* to put it in the proper form and decrement before freeing it.
|
||||||
|
*/
|
||||||
fullpath = build_path_from_dentry(dentry);
|
fullpath = build_path_from_dentry(dentry);
|
||||||
|
if (!fullpath) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto compose_mount_options_err;
|
||||||
|
}
|
||||||
|
++fullpath;
|
||||||
tkn_e = strchr(tkn_e + 1, '\\');
|
tkn_e = strchr(tkn_e + 1, '\\');
|
||||||
if (tkn_e || strlen(fullpath) - (ref->path_consumed)) {
|
if (tkn_e || (strlen(fullpath) - ref->path_consumed)) {
|
||||||
strncat(mountdata, &sep, 1);
|
strncat(mountdata, &sep, 1);
|
||||||
strcat(mountdata, "prefixpath=");
|
strcat(mountdata, "prefixpath=");
|
||||||
if (tkn_e)
|
if (tkn_e)
|
||||||
strcat(mountdata, tkn_e + 1);
|
strcat(mountdata, tkn_e + 1);
|
||||||
strcat(mountdata, fullpath + (ref->path_consumed));
|
strcat(mountdata, fullpath + ref->path_consumed);
|
||||||
}
|
}
|
||||||
|
--fullpath;
|
||||||
kfree(fullpath);
|
kfree(fullpath);
|
||||||
|
|
||||||
/*cFYI(1,("%s: parent mountdata: %s", __func__,sb_mountdata));*/
|
/*cFYI(1,("%s: parent mountdata: %s", __func__,sb_mountdata));*/
|
||||||
@ -217,6 +230,11 @@ static char *compose_mount_options(const char *sb_mountdata,
|
|||||||
compose_mount_options_out:
|
compose_mount_options_out:
|
||||||
kfree(srvIP);
|
kfree(srvIP);
|
||||||
return mountdata;
|
return mountdata;
|
||||||
|
|
||||||
|
compose_mount_options_err:
|
||||||
|
kfree(mountdata);
|
||||||
|
mountdata = ERR_PTR(rc);
|
||||||
|
goto compose_mount_options_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -309,13 +327,19 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
|
|||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The MSDFS spec states that paths in DFS referral requests and
|
||||||
|
* responses must be prefixed by a single '\' character instead of
|
||||||
|
* the double backslashes usually used in the UNC. This function
|
||||||
|
* gives us the latter, so we must adjust the result.
|
||||||
|
*/
|
||||||
full_path = build_path_from_dentry(dentry);
|
full_path = build_path_from_dentry(dentry);
|
||||||
if (full_path == NULL) {
|
if (full_path == NULL) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = get_dfs_path(xid, ses , full_path, cifs_sb->local_nls,
|
rc = get_dfs_path(xid, ses , full_path + 1, cifs_sb->local_nls,
|
||||||
&num_referrals, &referrals,
|
&num_referrals, &referrals,
|
||||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user