Commit 3ae3d4d5 authored by Steve French's avatar Steve French

Fix readlink of dfs junctions

parent 1f9ccaab
...@@ -1263,6 +1263,7 @@ typedef struct dfs_referral_level_3 { ...@@ -1263,6 +1263,7 @@ typedef struct dfs_referral_level_3 {
__u16 ServerType; /* 0x0001 = CIFS server */ __u16 ServerType; /* 0x0001 = CIFS server */
__u16 ReferralFlags; /* or proximity - not clear which since always set to zero - SNIA spec says 0x01 means strip off PathConsumed chars before submitting RequestFileName to remote node */ __u16 ReferralFlags; /* or proximity - not clear which since always set to zero - SNIA spec says 0x01 means strip off PathConsumed chars before submitting RequestFileName to remote node */
__u16 TimeToLive; __u16 TimeToLive;
__u16 Proximity;
__u16 DfsPathOffset; __u16 DfsPathOffset;
__u16 DfsAlternatePathOffset; __u16 DfsAlternatePathOffset;
__u16 NetworkAddressOffset; __u16 NetworkAddressOffset;
......
...@@ -127,13 +127,15 @@ extern int CIFSSMBUnixQPathInfo(const int xid, ...@@ -127,13 +127,15 @@ extern int CIFSSMBUnixQPathInfo(const int xid,
extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
const unsigned char *searchName, const unsigned char *searchName,
unsigned char **targetUNCs, unsigned char **targetUNCs,
int *number_of_UNC_in_array, unsigned int *number_of_UNC_in_array,
const struct nls_table *nls_codepage); const struct nls_table *nls_codepage);
extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, extern int connect_to_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);
extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
const char *old_path, const struct nls_table *nls_codepage,
unsigned int *pnum_referrals, unsigned char ** preferrals);
extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
struct statfs *FSData, struct statfs *FSData,
const struct nls_table *nls_codepage); const struct nls_table *nls_codepage);
......
...@@ -1625,15 +1625,18 @@ int ...@@ -1625,15 +1625,18 @@ int
CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
const unsigned char *searchName, const unsigned char *searchName,
unsigned char **targetUNCs, unsigned char **targetUNCs,
int *number_of_UNC_in_array, unsigned int *number_of_UNC_in_array,
const struct nls_table *nls_codepage) const struct nls_table *nls_codepage)
{ {
/* TRANS2_GET_DFS_REFERRAL */ /* TRANS2_GET_DFS_REFERRAL */
TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL; TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL; TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
struct dfs_referral_level_3 * referrals = NULL;
int rc = 0; int rc = 0;
int bytes_returned; int bytes_returned;
int name_len; int name_len;
unsigned int i;
char * temp;
*number_of_UNC_in_array = 0; *number_of_UNC_in_array = 0;
*targetUNCs = NULL; *targetUNCs = NULL;
...@@ -1701,6 +1704,76 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, ...@@ -1701,6 +1704,76 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
cFYI(1, ("Send error in GetDFSRefer = %d", rc)); cFYI(1, ("Send error in GetDFSRefer = %d", rc));
} else { /* decode response */ } else { /* decode response */
/* BB Add logic to parse referrals here */ /* BB Add logic to parse referrals here */
pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount);
cFYI(1,
("Decoding GetDFSRefer response. BCC: %d Offset %d",
pSMBr->ByteCount, pSMBr->DataOffset));
if ((pSMBr->ByteCount < 17) || (pSMBr->DataOffset > 512)) /* BB also check enough total bytes returned */
rc = -EIO; /* bad smb */
else {
referrals =
(struct dfs_referral_level_3 *)
(8 /* sizeof start of data block */ +
pSMBr->DataOffset +
(char *) &pSMBr->hdr.Protocol);
cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x",pSMBr->NumberOfReferrals,pSMBr->DFSFlags, referrals->ReferralSize,referrals->ServerType,referrals->ReferralFlags,referrals->TimeToLive));
/* BB This field is actually two bytes in from start of
data block so we could do safety check that DataBlock
begins at address of pSMBr->NumberOfReferrals */
*number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
/* BB Fix below so can return more than one referral */
if(*number_of_UNC_in_array > 1)
*number_of_UNC_in_array = 1;
/* get the length of the strings describing refs */
name_len = 0;
for(i=0;i<*number_of_UNC_in_array;i++) {
/* make sure that DfsPathOffset not past end */
referrals->DfsPathOffset = le16_to_cpu(referrals->DfsPathOffset);
if(referrals->DfsPathOffset > pSMBr->DataCount) {
/* if invalid referral, stop here and do
not try to copy any more */
*number_of_UNC_in_array = i;
break;
}
temp = ((char *)referrals) + referrals->DfsPathOffset;
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len += UniStrnlen((wchar_t *)temp,pSMBr->DataCount);
} else {
name_len += strnlen(temp,pSMBr->DataCount);
}
referrals++;
/* BB add check that referral pointer does not fall off end PDU */
}
/* BB add check for name_len bigger than bcc */
*targetUNCs =
kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
/* copy the ref strings */
referrals =
(struct dfs_referral_level_3 *)
(8 /* sizeof data hdr */ +
pSMBr->DataOffset +
(char *) &pSMBr->hdr.Protocol);
for(i=0;i<*number_of_UNC_in_array;i++) {
temp = ((char *)referrals) + referrals->DfsPathOffset;
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
cifs_strfromUCS_le(*targetUNCs,
(wchar_t *) temp, name_len, nls_codepage);
} else {
strncpy(*targetUNCs,temp,name_len);
}
/* BB update target_uncs pointers */
referrals++;
}
temp = *targetUNCs;
temp[name_len] = 0;
}
} }
if (pSMB) if (pSMB)
buf_release(pSMB); buf_release(pSMB);
......
...@@ -571,11 +571,32 @@ find_unc(__u32 new_target_ip_addr, char *uncName, char *userName) ...@@ -571,11 +571,32 @@ find_unc(__u32 new_target_ip_addr, char *uncName, char *userName)
int int
connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
const char *old_path, const struct nls_table *nls_codepage) const char *old_path, const struct nls_table *nls_codepage)
{
unsigned char *referrals = NULL;
unsigned int num_referrals;
int rc = 0;
rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
&num_referrals, &referrals);
/* 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 */
/* BB free memory for referrals string BB */
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, unsigned char ** preferrals)
{ {
char *temp_unc; char *temp_unc;
int rc = 0; int rc = 0;
int num_referrals = 0;
unsigned char *referrals = NULL; *pnum_referrals = 0;
if (pSesInfo->ipc_tid == 0) { if (pSesInfo->ipc_tid == 0) {
temp_unc = kmalloc(2 /* for slashes */ + temp_unc = kmalloc(2 /* for slashes */ +
...@@ -594,11 +615,10 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, ...@@ -594,11 +615,10 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
kfree(temp_unc); kfree(temp_unc);
} }
if (rc == 0) if (rc == 0)
rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, &referrals, rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
&num_referrals, nls_codepage); pnum_referrals, nls_codepage);
return -ENODEV; /* BB remove and add return code processing */
return rc;
} }
int setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_table * nls_info) int setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_table * nls_info)
......
...@@ -53,10 +53,6 @@ cifs_get_inode_info_unix(struct inode **pinode, ...@@ -53,10 +53,6 @@ cifs_get_inode_info_unix(struct inode **pinode,
/* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */ /* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */
if (rc) { if (rc) {
if (rc == -EREMOTE) { if (rc == -EREMOTE) {
/* rc = *//* CIFSGetDFSRefer(xid, pTcon->ses, search_path,
&referrals,
&num_referrals,
cifs_sb->local_nls); */
tmp_path = tmp_path =
kmalloc(strnlen kmalloc(strnlen
(pTcon->treeName, (pTcon->treeName,
...@@ -180,11 +176,6 @@ cifs_get_inode_info(struct inode **pinode, ...@@ -180,11 +176,6 @@ cifs_get_inode_info(struct inode **pinode,
/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
if (rc) { if (rc) {
if (rc == -EREMOTE) { if (rc == -EREMOTE) {
/* BB add call to new func rc = GetDFSReferral(); */
/* rc = *//* CIFSGetDFSRefer(xid, pTcon->ses, search_path,
&referrals,
&num_referrals,
cifs_sb->local_nls); */
tmp_path = tmp_path =
kmalloc(strnlen kmalloc(strnlen
(pTcon->treeName, (pTcon->treeName,
......
...@@ -113,6 +113,9 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) ...@@ -113,6 +113,9 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
/* BB Should we be using page symlink ops here? */ /* BB Should we be using page symlink ops here? */
if (rc == 0) { if (rc == 0) {
/* BB Add special case check for Samba DFS symlinks */
target_path[PATH_MAX-1] = 0; target_path[PATH_MAX-1] = 0;
rc = vfs_follow_link(nd, target_path); rc = vfs_follow_link(nd, target_path);
} }
...@@ -186,7 +189,10 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen) ...@@ -186,7 +189,10 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
char *full_path = NULL; char *full_path = NULL;
char *tmp_path = NULL;
char * tmpbuffer; char * tmpbuffer;
unsigned char * referrals = NULL;
int num_referrals = 0;
int len; int len;
__u16 fid; __u16 fid;
...@@ -206,6 +212,7 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen) ...@@ -206,6 +212,7 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
} }
/* BB add read reparse point symlink code and Unix extensions symlink code here BB */ /* BB add read reparse point symlink code and Unix extensions symlink code here BB */
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
...@@ -224,8 +231,36 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen) ...@@ -224,8 +231,36 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
if(CIFSSMBClose(xid, pTcon, fid)) { if(CIFSSMBClose(xid, pTcon, fid)) {
cFYI(1,("Error closing junction point (open for ioctl)")); cFYI(1,("Error closing junction point (open for ioctl)"));
} }
if(rc == -EIO) {
/* Query if DFS Junction */
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, &referrals);
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(referrals) {
cFYI(1,("referral string: %s ",referrals));
strncpy(tmpbuffer, referrals, len-1);
}
} }
kfree(tmp_path);
if(referrals) {
kfree(referrals);
}
}
/* 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? */
/* BB Should we be using page ops here? */ /* BB Should we be using page ops here? */
...@@ -238,10 +273,12 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen) ...@@ -238,10 +273,12 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
rc)); rc));
} }
if (tmpbuffer) if (tmpbuffer) {
kfree(tmpbuffer); kfree(tmpbuffer);
if (full_path) }
if (full_path) {
kfree(full_path); kfree(full_path);
}
FreeXid(xid); FreeXid(xid);
return rc; return rc;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment