Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 320b34e3 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents e3bf756e d9deef0a
Loading
Loading
Loading
Loading
+72 −69
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/vfs.h>
#include <linux/fs.h>
#include <linux/inet.h>
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifsfs.h"
@@ -48,58 +49,74 @@ void cifs_dfs_release_automount_timer(void)
}

/**
 * cifs_get_share_name	-	extracts share name from UNC
 * @node_name:	pointer to UNC string
 * cifs_build_devname - build a devicename from a UNC and optional prepath
 * @nodename:	pointer to UNC string
 * @prepath:	pointer to prefixpath (or NULL if there isn't one)
 *
 * Extracts sharename form full UNC.
 * i.e. strips from UNC trailing path that is not part of share
 * name and fixup missing '\' in the beginning of DFS node refferal
 * if necessary.
 * Returns pointer to share name on success or ERR_PTR on error.
 * Caller is responsible for freeing returned string.
 * Build a new cifs devicename after chasing a DFS referral. Allocate a buffer
 * big enough to hold the final thing. Copy the UNC from the nodename, and
 * concatenate the prepath onto the end of it if there is one.
 *
 * Returns pointer to the built string, or a ERR_PTR. Caller is responsible
 * 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;
	char *UNC;
	char *pSep;
	size_t pplen;
	size_t unclen;
	char *dev;
	char *pos;

	/* skip over any preceding delimiters */
	nodename += strspn(nodename, "\\");
	if (!*nodename)
		return ERR_PTR(-EINVAL);

	len = strlen(node_name);
	UNC = kmalloc(len+2 /*for term null and additional \ if it's missed */,
			 GFP_KERNEL);
	if (!UNC)
		return ERR_PTR(-ENOMEM);
	/* get length of UNC and set pos to last char */
	unclen = strlen(nodename);
	pos = nodename + unclen - 1;

	/* get share name and server name */
	if (node_name[1] != '\\') {
		UNC[0] = '\\';
		strncpy(UNC+1, node_name, len);
		len++;
		UNC[len] = 0;
	} else {
		strncpy(UNC, node_name, len);
		UNC[len] = 0;
	/* trim off any trailing delimiters */
	while (*pos == '\\') {
		--pos;
		--unclen;
	}

	/* find server name end */
	pSep = memchr(UNC+2, '\\', len-2);
	if (!pSep) {
		cifs_dbg(VFS, "%s: no server name end in node name: %s\n",
			 __func__, node_name);
		kfree(UNC);
		return ERR_PTR(-EINVAL);
	}
	/* 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);

	/* find sharename end */
	pSep++;
	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;
	pos = dev;
	/* add the initial "//" */
	*pos = '/';
	++pos;
	*pos = '/';
	++pos;

	/* copy in the UNC portion from referral */
	memcpy(pos, nodename, unclen);
	pos += unclen;

	/* copy the prefixpath remainder (if there is one) */
	if (pplen) {
		*pos = '/';
		++pos;
		memcpy(pos, prepath, pplen);
		pos += pplen;
	}

	return UNC;
	/* NULL terminator */
	*pos = '\0';

	convert_delimiter(dev, '/');
	return dev;
}


@@ -123,6 +140,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
{
	int rc;
	char *mountdata = NULL;
	const char *prepath = NULL;
	int md_len;
	char *tkn_e;
	char *srvIP = NULL;
@@ -132,7 +150,10 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
	if (sb_mountdata == NULL)
		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)) {
		rc = PTR_ERR(*devname);
		*devname = NULL;
@@ -146,11 +167,13 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
		goto compose_mount_options_err;
	}

	/* md_len = strlen(...) + 12 for 'sep+prefixpath='
	 * assuming that we have 'unc=' and 'ip=' in
	 * the original sb_mountdata
	/*
	 * In most cases, we'll be building a shorter string than the original,
	 * 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);
	if (mountdata == NULL) {
		rc = -ENOMEM;
@@ -195,26 +218,6 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
		strncat(mountdata, &sep, 1);
	strcat(mountdata, "ip=");
	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: submount mountdata: %s\n", __func__, mountdata );*/
+0 −3
Original line number Diff line number Diff line
@@ -372,9 +372,6 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
	cifs_show_security(s, tcon->ses->server);
	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)
		seq_printf(s, ",multiuser");
	else if (tcon->ses->user_name)
+14 −9
Original line number Diff line number Diff line
@@ -1061,6 +1061,7 @@ static int cifs_parse_security_flavors(char *value,
#endif
	case Opt_sec_none:
		vol->nullauth = 1;
		vol->secFlg |= CIFSSEC_MAY_NTLM;
		break;
	default:
		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->backupgid_specified = false; /* no backup intent for a group */

	/*
	 * For now, we ignore -EINVAL errors under the assumption that the
	 * unc= and prefixpath= options will be usable.
	 */
	if (cifs_parse_devname(devname, vol) == -ENOMEM) {
		printk(KERN_ERR "CIFS: Unable to allocate memory to parse "
				"device string.\n");
		goto out_nomem;
	switch (cifs_parse_devname(devname, vol)) {
	case 0:
		break;
	case -ENOMEM:
		cifs_dbg(VFS, "Unable to allocate memory for devname.\n");
		goto cifs_parse_mount_err;
	case -EINVAL:
		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) {
@@ -1826,7 +1831,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
	}
#endif
	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;
	}

+2 −2
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@

/**
 * 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.
 *
 * 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;

	/* Search for server name delimiter */
	sep = memchr(hostname, '\\', len);
	sep = memchr(hostname, '/', len);
	if (sep)
		len = sep - hostname;
	else