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

Commit 646dd539 authored by Steve French's avatar Steve French
Browse files

[CIFS] Fix paths when share is in DFS to include proper prefix



Some versions of Samba (3.2-pre e.g.) are stricter about checking to make sure that
paths in DFS name spaces are sent in the form \\server\share\dir\subdir ...
instead of \dir\subdir

Acked-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent 35fc37d5
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -150,9 +150,6 @@ extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
			unsigned int *number_of_UNC_in_array,
			const struct nls_table *nls_codepage, int remap);

extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
			const char *old_path,
			const struct nls_table *nls_codepage, int remap);
extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
			const char *old_path,
			const struct nls_table *nls_codepage,
+3 −23
Original line number Diff line number Diff line
@@ -1418,27 +1418,6 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
	return NULL;
}

int
connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
		    const char *old_path, const struct nls_table *nls_codepage,
		    int remap)
{
	struct dfs_info3_param *referrals = NULL;
	unsigned int num_referrals;
	int rc = 0;

	rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage,
			&num_referrals, &referrals, remap);

	/* BB Add in code to: if valid refrl, if not ip address contact
		the helper that resolves tcp names, mount to it, try to
		tcon to it unmount it if fail */

	kfree(referrals);

	return rc;
}

int
get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
	     const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
@@ -2161,10 +2140,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
				if ((strchr(volume_info.UNC + 3, '\\') == NULL)
				    && (strchr(volume_info.UNC + 3, '/') ==
					NULL)) {
					rc = connect_to_dfs_path(xid, pSesInfo,
/*					rc = connect_to_dfs_path(xid, pSesInfo,
						"", cifs_sb->local_nls,
						cifs_sb->mnt_cifs_flags &
						  CIFS_MOUNT_MAP_SPECIAL_CHR);
						  CIFS_MOUNT_MAP_SPECIAL_CHR);*/
					cFYI(1, ("DFS root not supported"));
					rc = -ENODEV;
					goto out;
				} else {
+23 −5
Original line number Diff line number Diff line
@@ -49,18 +49,25 @@ build_path_from_dentry(struct dentry *direntry)
	struct dentry *temp;
	int namelen;
	int pplen;
	int dfsplen;
	char *full_path;
	char dirsep;
	struct cifs_sb_info *cifs_sb;

	if (direntry == NULL)
		return NULL;  /* not much we can do if dentry is freed and
		we need to reopen the file after it was closed implicitly
		when the server crashed */

	dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb));
	pplen = CIFS_SB(direntry->d_sb)->prepathlen;
	cifs_sb = CIFS_SB(direntry->d_sb);
	dirsep = CIFS_DIR_SEP(cifs_sb);
	pplen = cifs_sb->prepathlen;
	if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS))
		dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1);
	else
		dfsplen = 0;
cifs_bp_rename_retry:
	namelen = pplen;
	namelen = pplen + dfsplen;
	for (temp = direntry; !IS_ROOT(temp);) {
		namelen += (1 + temp->d_name.len);
		temp = temp->d_parent;
@@ -91,7 +98,7 @@ build_path_from_dentry(struct dentry *direntry)
			return NULL;
		}
	}
	if (namelen != pplen) {
	if (namelen != pplen + dfsplen) {
		cERROR(1,
		       ("did not end path lookup where expected namelen is %d",
			namelen));
@@ -107,7 +114,18 @@ build_path_from_dentry(struct dentry *direntry)
	   since the '\' is a valid posix character so we can not switch
	   those safely to '/' if any are found in the middle of the prepath */
	/* BB test paths to Windows with '/' in the midst of prepath */
	strncpy(full_path, CIFS_SB(direntry->d_sb)->prepath, pplen);

	if (dfsplen) {
		strncpy(full_path, cifs_sb->tcon->treeName, dfsplen);
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
			int i;
			for (i = 0; i < dfsplen; i++) {
				if (full_path[i] == '\\')
					full_path[i] = '/';
			}
		}
	}
	strncpy(full_path + dfsplen, CIFS_SB(direntry->d_sb)->prepath, pplen);
	return full_path;
}

+8 −57
Original line number Diff line number Diff line
@@ -161,52 +161,18 @@ static void cifs_unix_info_to_inode(struct inode *inode,
	spin_unlock(&inode->i_lock);
}

static const unsigned char *cifs_get_search_path(struct cifs_sb_info *cifs_sb,
						const char *search_path)
{
	int tree_len;
	int path_len;
	int i;
	char *tmp_path;
	struct cifsTconInfo *pTcon = cifs_sb->tcon;

	if (!(pTcon->Flags & SMB_SHARE_IS_IN_DFS))
		return search_path;

	/* use full path name for working with DFS */
	tree_len = strnlen(pTcon->treeName, MAX_TREE_SIZE + 1);
	path_len = strnlen(search_path, MAX_PATHCONF);

	tmp_path = kmalloc(tree_len+path_len+1, GFP_KERNEL);
	if (tmp_path == NULL)
		return search_path;

	strncpy(tmp_path, pTcon->treeName, tree_len);
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
		for (i = 0; i < tree_len; i++) {
			if (tmp_path[i] == '\\')
				tmp_path[i] = '/';
		}
	strncpy(tmp_path+tree_len, search_path, path_len);
	tmp_path[tree_len+path_len] = 0;
	return tmp_path;
}

int cifs_get_inode_info_unix(struct inode **pinode,
	const unsigned char *search_path, struct super_block *sb, int xid)
	const unsigned char *full_path, struct super_block *sb, int xid)
{
	int rc = 0;
	FILE_UNIX_BASIC_INFO findData;
	struct cifsTconInfo *pTcon;
	struct inode *inode;
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
	const unsigned char *full_path;
	bool is_dfs_referral = false;

	pTcon = cifs_sb->tcon;
	cFYI(1, ("Getting info on %s", search_path));

	full_path = cifs_get_search_path(cifs_sb, search_path);
	cFYI(1, ("Getting info on %s", full_path));

try_again_CIFSSMBUnixQPathInfo:
	/* could have done a find first instead but this returns more info */
@@ -218,10 +184,6 @@ int cifs_get_inode_info_unix(struct inode **pinode,
	if (rc) {
		if (rc == -EREMOTE && !is_dfs_referral) {
			is_dfs_referral = true;
			if (full_path != search_path) {
				kfree(full_path);
				full_path = search_path;
			}
			goto try_again_CIFSSMBUnixQPathInfo;
		}
		goto cgiiu_exit;
@@ -271,8 +233,6 @@ int cifs_get_inode_info_unix(struct inode **pinode,
		cifs_set_ops(inode, is_dfs_referral);
	}
cgiiu_exit:
	if (full_path != search_path)
		kfree(full_path);
	return rc;
}

@@ -380,20 +340,19 @@ static int get_sfu_mode(struct inode *inode,
}

int cifs_get_inode_info(struct inode **pinode,
	const unsigned char *search_path, FILE_ALL_INFO *pfindData,
	const unsigned char *full_path, FILE_ALL_INFO *pfindData,
	struct super_block *sb, int xid, const __u16 *pfid)
{
	int rc = 0;
	struct cifsTconInfo *pTcon;
	struct inode *inode;
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
	const unsigned char *full_path = NULL;
	char *buf = NULL;
	bool adjustTZ = false;
	bool is_dfs_referral = false;

	pTcon = cifs_sb->tcon;
	cFYI(1, ("Getting info on %s", search_path));
	cFYI(1, ("Getting info on %s", full_path));

	if ((pfindData == NULL) && (*pinode != NULL)) {
		if (CIFS_I(*pinode)->clientCanCacheRead) {
@@ -409,8 +368,6 @@ int cifs_get_inode_info(struct inode **pinode,
			return -ENOMEM;
		pfindData = (FILE_ALL_INFO *)buf;

		full_path = cifs_get_search_path(cifs_sb, search_path);

try_again_CIFSSMBQPathInfo:
		/* could do find first instead but this returns more info */
		rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
@@ -432,10 +389,6 @@ int cifs_get_inode_info(struct inode **pinode,
	if (rc) {
		if (rc == -EREMOTE && !is_dfs_referral) {
			is_dfs_referral = true;
			if (full_path != search_path) {
				kfree(full_path);
				full_path = search_path;
			}
			goto try_again_CIFSSMBQPathInfo;
		}
		goto cgii_exit;
@@ -470,7 +423,7 @@ int cifs_get_inode_info(struct inode **pinode,
				__u64 inode_num;

				rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
					search_path, &inode_num,
					full_path, &inode_num,
					cifs_sb->local_nls,
					cifs_sb->mnt_cifs_flags &
						CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -539,7 +492,7 @@ int cifs_get_inode_info(struct inode **pinode,
			   (cifsInfo->cifsAttrs & ATTR_SYSTEM)) {
			if (decode_sfu_inode(inode,
					 le64_to_cpu(pfindData->EndOfFile),
					 search_path,
					 full_path,
					 cifs_sb, xid))
				cFYI(1, ("Unrecognized sfu inode type"));

@@ -582,12 +535,12 @@ int cifs_get_inode_info(struct inode **pinode,
		/* fill in 0777 bits from ACL */
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
			cFYI(1, ("Getting mode bits from ACL"));
			acl_to_uid_mode(inode, search_path, pfid);
			acl_to_uid_mode(inode, full_path, pfid);
		}
#endif
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
			/* fill in remaining high mode bits e.g. SUID, VTX */
			get_sfu_mode(inode, search_path, cifs_sb, xid);
			get_sfu_mode(inode, full_path, cifs_sb, xid);
		} else if (atomic_read(&cifsInfo->inUse) == 0) {
			inode->i_uid = cifs_sb->mnt_uid;
			inode->i_gid = cifs_sb->mnt_gid;
@@ -599,8 +552,6 @@ int cifs_get_inode_info(struct inode **pinode,
		cifs_set_ops(inode, is_dfs_referral);
	}
cgii_exit:
	if (full_path != search_path)
		kfree(full_path);
	kfree(buf);
	return rc;
}
+3 −39
Original line number Diff line number Diff line
@@ -295,45 +295,9 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
				cFYI(1, ("Error closing junction point "
					 "(open for ioctl)"));
			}
			/* BB unwind this long, nested function, or remove BB */
			if (rc == -EIO) {
				/* Query if DFS Junction */
				unsigned int num_referrals = 0;
				struct dfs_info3_param *refs = NULL;
				tmp_path =
					kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
						GFP_KERNEL);
				if (tmp_path) {
					strncpy(tmp_path, pTcon->treeName,
						MAX_TREE_SIZE);
					strncat(tmp_path, full_path,
						MAX_PATHCONF);
					rc = get_dfs_path(xid, pTcon->ses,
						tmp_path,
						cifs_sb->local_nls,
						&num_referrals, &refs,
						cifs_sb->mnt_cifs_flags &
						    CIFS_MOUNT_MAP_SPECIAL_CHR);
					cFYI(1, ("Get DFS for %s rc = %d ",
						tmp_path, rc));
					if ((num_referrals == 0) && (rc == 0))
						rc = -EACCES;
					else {
						cFYI(1, ("num referral: %d",
							num_referrals));
						if (refs && refs->path_name) {
							strncpy(tmpbuffer,
								refs->path_name,
								len-1);
						}
					}
					kfree(refs);
					kfree(tmp_path);
}
				/* BB add code like else decode referrals
				then memcpy to tmpbuffer and free referrals
				string array BB */
			}
			/* If it is a DFS junction earlier we would have gotten
			   PATH_NOT_COVERED returned from server so we do
			   not need to request the DFS info here */
		}
	}
	/* BB Anything else to do to handle recursive links? */