mirror of
https://github.com/adulau/aha.git
synced 2024-12-29 04:06:22 +00:00
[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:
parent
35fc37d517
commit
646dd53987
5 changed files with 37 additions and 127 deletions
|
@ -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,
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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? */
|
||||||
|
|
Loading…
Reference in a new issue