Merge branch 'for-3.10' of git://git.samba.org/sfrench/cifs-2.6
Pull CIFS fixes from Steve French: "Fixes for a couple of DFS problems, a problem with extended security negotiation and two other small cifs fixes" * 'for-3.10' of git://git.samba.org/sfrench/cifs-2.6: cifs: fix composing of mount options for DFS referrals cifs: stop printing the unc= option in /proc/mounts cifs: fix error handling when calling cifs_parse_devname cifs: allow sec=none mounts to work against servers that don't support extended security cifs: fix potential buffer overrun when composing a new options string cifs: only set ops for inodes in I_NEW state
This commit is contained in:
commit
320b34e3e0
4 changed files with 88 additions and 83 deletions
|
@ -18,6 +18,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/vfs.h>
|
#include <linux/vfs.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
|
#include <linux/inet.h>
|
||||||
#include "cifsglob.h"
|
#include "cifsglob.h"
|
||||||
#include "cifsproto.h"
|
#include "cifsproto.h"
|
||||||
#include "cifsfs.h"
|
#include "cifsfs.h"
|
||||||
|
@ -48,58 +49,74 @@ void cifs_dfs_release_automount_timer(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cifs_get_share_name - extracts share name from UNC
|
* cifs_build_devname - build a devicename from a UNC and optional prepath
|
||||||
* @node_name: pointer to UNC string
|
* @nodename: pointer to UNC string
|
||||||
|
* @prepath: pointer to prefixpath (or NULL if there isn't one)
|
||||||
*
|
*
|
||||||
* Extracts sharename form full UNC.
|
* Build a new cifs devicename after chasing a DFS referral. Allocate a buffer
|
||||||
* i.e. strips from UNC trailing path that is not part of share
|
* big enough to hold the final thing. Copy the UNC from the nodename, and
|
||||||
* name and fixup missing '\' in the beginning of DFS node refferal
|
* concatenate the prepath onto the end of it if there is one.
|
||||||
* if necessary.
|
*
|
||||||
* Returns pointer to share name on success or ERR_PTR on error.
|
* Returns pointer to the built string, or a ERR_PTR. Caller is responsible
|
||||||
* Caller is responsible for freeing returned string.
|
* for freeing the returned string.
|
||||||
*/
|
*/
|
||||||
static char *cifs_get_share_name(const char *node_name)
|
static char *
|
||||||
|
cifs_build_devname(char *nodename, const char *prepath)
|
||||||
{
|
{
|
||||||
int len;
|
size_t pplen;
|
||||||
char *UNC;
|
size_t unclen;
|
||||||
char *pSep;
|
char *dev;
|
||||||
|
char *pos;
|
||||||
|
|
||||||
len = strlen(node_name);
|
/* skip over any preceding delimiters */
|
||||||
UNC = kmalloc(len+2 /*for term null and additional \ if it's missed */,
|
nodename += strspn(nodename, "\\");
|
||||||
GFP_KERNEL);
|
if (!*nodename)
|
||||||
if (!UNC)
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
|
/* get length of UNC and set pos to last char */
|
||||||
|
unclen = strlen(nodename);
|
||||||
|
pos = nodename + unclen - 1;
|
||||||
|
|
||||||
|
/* trim off any trailing delimiters */
|
||||||
|
while (*pos == '\\') {
|
||||||
|
--pos;
|
||||||
|
--unclen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate a buffer:
|
||||||
|
* +2 for preceding "//"
|
||||||
|
* +1 for delimiter between UNC and prepath
|
||||||
|
* +1 for trailing NULL
|
||||||
|
*/
|
||||||
|
pplen = prepath ? strlen(prepath) : 0;
|
||||||
|
dev = kmalloc(2 + unclen + 1 + pplen + 1, GFP_KERNEL);
|
||||||
|
if (!dev)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
/* get share name and server name */
|
pos = dev;
|
||||||
if (node_name[1] != '\\') {
|
/* add the initial "//" */
|
||||||
UNC[0] = '\\';
|
*pos = '/';
|
||||||
strncpy(UNC+1, node_name, len);
|
++pos;
|
||||||
len++;
|
*pos = '/';
|
||||||
UNC[len] = 0;
|
++pos;
|
||||||
} else {
|
|
||||||
strncpy(UNC, node_name, len);
|
/* copy in the UNC portion from referral */
|
||||||
UNC[len] = 0;
|
memcpy(pos, nodename, unclen);
|
||||||
|
pos += unclen;
|
||||||
|
|
||||||
|
/* copy the prefixpath remainder (if there is one) */
|
||||||
|
if (pplen) {
|
||||||
|
*pos = '/';
|
||||||
|
++pos;
|
||||||
|
memcpy(pos, prepath, pplen);
|
||||||
|
pos += pplen;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find server name end */
|
/* NULL terminator */
|
||||||
pSep = memchr(UNC+2, '\\', len-2);
|
*pos = '\0';
|
||||||
if (!pSep) {
|
|
||||||
cifs_dbg(VFS, "%s: no server name end in node name: %s\n",
|
|
||||||
__func__, node_name);
|
|
||||||
kfree(UNC);
|
|
||||||
return ERR_PTR(-EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* find sharename end */
|
convert_delimiter(dev, '/');
|
||||||
pSep++;
|
return dev;
|
||||||
pSep = memchr(UNC+(pSep-UNC), '\\', len-(pSep-UNC));
|
|
||||||
if (pSep) {
|
|
||||||
/* trim path up to sharename end
|
|
||||||
* now we have share name in UNC */
|
|
||||||
*pSep = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return UNC;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -123,6 +140,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
char *mountdata = NULL;
|
char *mountdata = NULL;
|
||||||
|
const char *prepath = NULL;
|
||||||
int md_len;
|
int md_len;
|
||||||
char *tkn_e;
|
char *tkn_e;
|
||||||
char *srvIP = NULL;
|
char *srvIP = NULL;
|
||||||
|
@ -132,7 +150,10 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
|
||||||
if (sb_mountdata == NULL)
|
if (sb_mountdata == NULL)
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
*devname = cifs_get_share_name(ref->node_name);
|
if (strlen(fullpath) - ref->path_consumed)
|
||||||
|
prepath = fullpath + ref->path_consumed;
|
||||||
|
|
||||||
|
*devname = cifs_build_devname(ref->node_name, prepath);
|
||||||
if (IS_ERR(*devname)) {
|
if (IS_ERR(*devname)) {
|
||||||
rc = PTR_ERR(*devname);
|
rc = PTR_ERR(*devname);
|
||||||
*devname = NULL;
|
*devname = NULL;
|
||||||
|
@ -146,12 +167,14 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
|
||||||
goto compose_mount_options_err;
|
goto compose_mount_options_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* md_len = strlen(...) + 12 for 'sep+prefixpath='
|
/*
|
||||||
* assuming that we have 'unc=' and 'ip=' in
|
* In most cases, we'll be building a shorter string than the original,
|
||||||
* the original sb_mountdata
|
* but we do have to assume that the address in the ip= option may be
|
||||||
|
* much longer than the original. Add the max length of an address
|
||||||
|
* string to the length of the original string to allow for worst case.
|
||||||
*/
|
*/
|
||||||
md_len = strlen(sb_mountdata) + rc + strlen(ref->node_name) + 12;
|
md_len = strlen(sb_mountdata) + INET6_ADDRSTRLEN;
|
||||||
mountdata = kzalloc(md_len+1, GFP_KERNEL);
|
mountdata = kzalloc(md_len + 1, GFP_KERNEL);
|
||||||
if (mountdata == NULL) {
|
if (mountdata == NULL) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto compose_mount_options_err;
|
goto compose_mount_options_err;
|
||||||
|
@ -195,26 +218,6 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
|
||||||
strncat(mountdata, &sep, 1);
|
strncat(mountdata, &sep, 1);
|
||||||
strcat(mountdata, "ip=");
|
strcat(mountdata, "ip=");
|
||||||
strcat(mountdata, srvIP);
|
strcat(mountdata, srvIP);
|
||||||
strncat(mountdata, &sep, 1);
|
|
||||||
strcat(mountdata, "unc=");
|
|
||||||
strcat(mountdata, *devname);
|
|
||||||
|
|
||||||
/* find & copy prefixpath */
|
|
||||||
tkn_e = strchr(ref->node_name + 2, '\\');
|
|
||||||
if (tkn_e == NULL) {
|
|
||||||
/* invalid unc, missing share name*/
|
|
||||||
rc = -EINVAL;
|
|
||||||
goto compose_mount_options_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
tkn_e = strchr(tkn_e + 1, '\\');
|
|
||||||
if (tkn_e || (strlen(fullpath) - ref->path_consumed)) {
|
|
||||||
strncat(mountdata, &sep, 1);
|
|
||||||
strcat(mountdata, "prefixpath=");
|
|
||||||
if (tkn_e)
|
|
||||||
strcat(mountdata, tkn_e + 1);
|
|
||||||
strcat(mountdata, fullpath + ref->path_consumed);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*cifs_dbg(FYI, "%s: parent mountdata: %s\n", __func__, sb_mountdata);*/
|
/*cifs_dbg(FYI, "%s: parent mountdata: %s\n", __func__, sb_mountdata);*/
|
||||||
/*cifs_dbg(FYI, "%s: submount mountdata: %s\n", __func__, mountdata );*/
|
/*cifs_dbg(FYI, "%s: submount mountdata: %s\n", __func__, mountdata );*/
|
||||||
|
|
|
@ -372,9 +372,6 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
|
||||||
cifs_show_security(s, tcon->ses->server);
|
cifs_show_security(s, tcon->ses->server);
|
||||||
cifs_show_cache_flavor(s, cifs_sb);
|
cifs_show_cache_flavor(s, cifs_sb);
|
||||||
|
|
||||||
seq_printf(s, ",unc=");
|
|
||||||
seq_escape(s, tcon->treeName, " \t\n\\");
|
|
||||||
|
|
||||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)
|
||||||
seq_printf(s, ",multiuser");
|
seq_printf(s, ",multiuser");
|
||||||
else if (tcon->ses->user_name)
|
else if (tcon->ses->user_name)
|
||||||
|
|
|
@ -1061,6 +1061,7 @@ static int cifs_parse_security_flavors(char *value,
|
||||||
#endif
|
#endif
|
||||||
case Opt_sec_none:
|
case Opt_sec_none:
|
||||||
vol->nullauth = 1;
|
vol->nullauth = 1;
|
||||||
|
vol->secFlg |= CIFSSEC_MAY_NTLM;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
cifs_dbg(VFS, "bad security option: %s\n", value);
|
cifs_dbg(VFS, "bad security option: %s\n", value);
|
||||||
|
@ -1257,14 +1258,18 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
|
||||||
vol->backupuid_specified = false; /* no backup intent for a user */
|
vol->backupuid_specified = false; /* no backup intent for a user */
|
||||||
vol->backupgid_specified = false; /* no backup intent for a group */
|
vol->backupgid_specified = false; /* no backup intent for a group */
|
||||||
|
|
||||||
/*
|
switch (cifs_parse_devname(devname, vol)) {
|
||||||
* For now, we ignore -EINVAL errors under the assumption that the
|
case 0:
|
||||||
* unc= and prefixpath= options will be usable.
|
break;
|
||||||
*/
|
case -ENOMEM:
|
||||||
if (cifs_parse_devname(devname, vol) == -ENOMEM) {
|
cifs_dbg(VFS, "Unable to allocate memory for devname.\n");
|
||||||
printk(KERN_ERR "CIFS: Unable to allocate memory to parse "
|
goto cifs_parse_mount_err;
|
||||||
"device string.\n");
|
case -EINVAL:
|
||||||
goto out_nomem;
|
cifs_dbg(VFS, "Malformed UNC in devname.\n");
|
||||||
|
goto cifs_parse_mount_err;
|
||||||
|
default:
|
||||||
|
cifs_dbg(VFS, "Unknown error parsing devname.\n");
|
||||||
|
goto cifs_parse_mount_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((data = strsep(&options, separator)) != NULL) {
|
while ((data = strsep(&options, separator)) != NULL) {
|
||||||
|
@ -1826,7 +1831,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (!vol->UNC) {
|
if (!vol->UNC) {
|
||||||
cifs_dbg(VFS, "CIFS mount error: No usable UNC path provided in device string or in unc= option!\n");
|
cifs_dbg(VFS, "CIFS mount error: No usable UNC path provided in device string!\n");
|
||||||
goto cifs_parse_mount_err;
|
goto cifs_parse_mount_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dns_resolve_server_name_to_ip - Resolve UNC server name to ip address.
|
* dns_resolve_server_name_to_ip - Resolve UNC server name to ip address.
|
||||||
* @unc: UNC path specifying the server
|
* @unc: UNC path specifying the server (with '/' as delimiter)
|
||||||
* @ip_addr: Where to return the IP address.
|
* @ip_addr: Where to return the IP address.
|
||||||
*
|
*
|
||||||
* The IP address will be returned in string form, and the caller is
|
* The IP address will be returned in string form, and the caller is
|
||||||
|
@ -64,7 +64,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
|
||||||
hostname = unc + 2;
|
hostname = unc + 2;
|
||||||
|
|
||||||
/* Search for server name delimiter */
|
/* Search for server name delimiter */
|
||||||
sep = memchr(hostname, '\\', len);
|
sep = memchr(hostname, '/', len);
|
||||||
if (sep)
|
if (sep)
|
||||||
len = sep - hostname;
|
len = sep - hostname;
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in a new issue