[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: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
Steve French 2008-05-15 01:50:56 +00:00
parent 35fc37d517
commit 646dd53987
5 changed files with 37 additions and 127 deletions

View file

@ -150,9 +150,6 @@ extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
unsigned int *number_of_UNC_in_array, unsigned int *number_of_UNC_in_array,
const struct nls_table *nls_codepage, int remap); 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, extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
const char *old_path, const char *old_path,
const struct nls_table *nls_codepage, const struct nls_table *nls_codepage,

View file

@ -1418,27 +1418,6 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
return NULL; 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 int
get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
const struct nls_table *nls_codepage, unsigned int *pnum_referrals, 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) if ((strchr(volume_info.UNC + 3, '\\') == NULL)
&& (strchr(volume_info.UNC + 3, '/') == && (strchr(volume_info.UNC + 3, '/') ==
NULL)) { NULL)) {
rc = connect_to_dfs_path(xid, pSesInfo, /* rc = connect_to_dfs_path(xid, pSesInfo,
"", cifs_sb->local_nls, "", cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);*/
cFYI(1, ("DFS root not supported"));
rc = -ENODEV; rc = -ENODEV;
goto out; goto out;
} else { } else {

View file

@ -49,18 +49,25 @@ build_path_from_dentry(struct dentry *direntry)
struct dentry *temp; struct dentry *temp;
int namelen; int namelen;
int pplen; int pplen;
int dfsplen;
char *full_path; char *full_path;
char dirsep; char dirsep;
struct cifs_sb_info *cifs_sb;
if (direntry == NULL) if (direntry == NULL)
return NULL; /* not much we can do if dentry is freed and return NULL; /* not much we can do if dentry is freed and
we need to reopen the file after it was closed implicitly we need to reopen the file after it was closed implicitly
when the server crashed */ when the server crashed */
dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb)); cifs_sb = CIFS_SB(direntry->d_sb);
pplen = CIFS_SB(direntry->d_sb)->prepathlen; 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: cifs_bp_rename_retry:
namelen = pplen; namelen = pplen + dfsplen;
for (temp = direntry; !IS_ROOT(temp);) { for (temp = direntry; !IS_ROOT(temp);) {
namelen += (1 + temp->d_name.len); namelen += (1 + temp->d_name.len);
temp = temp->d_parent; temp = temp->d_parent;
@ -91,7 +98,7 @@ cifs_bp_rename_retry:
return NULL; return NULL;
} }
} }
if (namelen != pplen) { if (namelen != pplen + dfsplen) {
cERROR(1, cERROR(1,
("did not end path lookup where expected namelen is %d", ("did not end path lookup where expected namelen is %d",
namelen)); namelen));
@ -107,7 +114,18 @@ cifs_bp_rename_retry:
since the '\' is a valid posix character so we can not switch 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 */ those safely to '/' if any are found in the middle of the prepath */
/* BB test paths to Windows with '/' in the midst of 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; return full_path;
} }

View file

@ -161,52 +161,18 @@ static void cifs_unix_info_to_inode(struct inode *inode,
spin_unlock(&inode->i_lock); 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, 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; int rc = 0;
FILE_UNIX_BASIC_INFO findData; FILE_UNIX_BASIC_INFO findData;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
struct inode *inode; struct inode *inode;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
const unsigned char *full_path;
bool is_dfs_referral = false; bool is_dfs_referral = false;
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
cFYI(1, ("Getting info on %s", search_path)); cFYI(1, ("Getting info on %s", full_path));
full_path = cifs_get_search_path(cifs_sb, search_path);
try_again_CIFSSMBUnixQPathInfo: try_again_CIFSSMBUnixQPathInfo:
/* could have done a find first instead but this returns more info */ /* could have done a find first instead but this returns more info */
@ -218,10 +184,6 @@ try_again_CIFSSMBUnixQPathInfo:
if (rc) { if (rc) {
if (rc == -EREMOTE && !is_dfs_referral) { if (rc == -EREMOTE && !is_dfs_referral) {
is_dfs_referral = true; is_dfs_referral = true;
if (full_path != search_path) {
kfree(full_path);
full_path = search_path;
}
goto try_again_CIFSSMBUnixQPathInfo; goto try_again_CIFSSMBUnixQPathInfo;
} }
goto cgiiu_exit; goto cgiiu_exit;
@ -271,8 +233,6 @@ try_again_CIFSSMBUnixQPathInfo:
cifs_set_ops(inode, is_dfs_referral); cifs_set_ops(inode, is_dfs_referral);
} }
cgiiu_exit: cgiiu_exit:
if (full_path != search_path)
kfree(full_path);
return rc; return rc;
} }
@ -380,20 +340,19 @@ static int get_sfu_mode(struct inode *inode,
} }
int cifs_get_inode_info(struct inode **pinode, 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) struct super_block *sb, int xid, const __u16 *pfid)
{ {
int rc = 0; int rc = 0;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
struct inode *inode; struct inode *inode;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
const unsigned char *full_path = NULL;
char *buf = NULL; char *buf = NULL;
bool adjustTZ = false; bool adjustTZ = false;
bool is_dfs_referral = false; bool is_dfs_referral = false;
pTcon = cifs_sb->tcon; 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 ((pfindData == NULL) && (*pinode != NULL)) {
if (CIFS_I(*pinode)->clientCanCacheRead) { if (CIFS_I(*pinode)->clientCanCacheRead) {
@ -409,8 +368,6 @@ int cifs_get_inode_info(struct inode **pinode,
return -ENOMEM; return -ENOMEM;
pfindData = (FILE_ALL_INFO *)buf; pfindData = (FILE_ALL_INFO *)buf;
full_path = cifs_get_search_path(cifs_sb, search_path);
try_again_CIFSSMBQPathInfo: try_again_CIFSSMBQPathInfo:
/* could do find first instead but this returns more info */ /* could do find first instead but this returns more info */
rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData, rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
@ -432,10 +389,6 @@ try_again_CIFSSMBQPathInfo:
if (rc) { if (rc) {
if (rc == -EREMOTE && !is_dfs_referral) { if (rc == -EREMOTE && !is_dfs_referral) {
is_dfs_referral = true; is_dfs_referral = true;
if (full_path != search_path) {
kfree(full_path);
full_path = search_path;
}
goto try_again_CIFSSMBQPathInfo; goto try_again_CIFSSMBQPathInfo;
} }
goto cgii_exit; goto cgii_exit;
@ -470,7 +423,7 @@ try_again_CIFSSMBQPathInfo:
__u64 inode_num; __u64 inode_num;
rc1 = CIFSGetSrvInodeNumber(xid, pTcon, rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
search_path, &inode_num, full_path, &inode_num,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
@ -539,7 +492,7 @@ try_again_CIFSSMBQPathInfo:
(cifsInfo->cifsAttrs & ATTR_SYSTEM)) { (cifsInfo->cifsAttrs & ATTR_SYSTEM)) {
if (decode_sfu_inode(inode, if (decode_sfu_inode(inode,
le64_to_cpu(pfindData->EndOfFile), le64_to_cpu(pfindData->EndOfFile),
search_path, full_path,
cifs_sb, xid)) cifs_sb, xid))
cFYI(1, ("Unrecognized sfu inode type")); cFYI(1, ("Unrecognized sfu inode type"));
@ -582,12 +535,12 @@ try_again_CIFSSMBQPathInfo:
/* fill in 0777 bits from ACL */ /* fill in 0777 bits from ACL */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
cFYI(1, ("Getting mode bits from 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 #endif
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
/* fill in remaining high mode bits e.g. SUID, VTX */ /* 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) { } else if (atomic_read(&cifsInfo->inUse) == 0) {
inode->i_uid = cifs_sb->mnt_uid; inode->i_uid = cifs_sb->mnt_uid;
inode->i_gid = cifs_sb->mnt_gid; inode->i_gid = cifs_sb->mnt_gid;
@ -599,8 +552,6 @@ try_again_CIFSSMBQPathInfo:
cifs_set_ops(inode, is_dfs_referral); cifs_set_ops(inode, is_dfs_referral);
} }
cgii_exit: cgii_exit:
if (full_path != search_path)
kfree(full_path);
kfree(buf); kfree(buf);
return rc; return rc;
} }

View file

@ -295,45 +295,9 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
cFYI(1, ("Error closing junction point " cFYI(1, ("Error closing junction point "
"(open for ioctl)")); "(open for ioctl)"));
} }
/* BB unwind this long, nested function, or remove BB */ /* If it is a DFS junction earlier we would have gotten
if (rc == -EIO) { PATH_NOT_COVERED returned from server so we do
/* Query if DFS Junction */ not need to request the DFS info here */
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 */
}
} }
} }
/* BB Anything else to do to handle recursive links? */ /* BB Anything else to do to handle recursive links? */