forked from luck/tmp_suning_uos_patched
CIFS: move DFS response parsing out of SMB1 code
since the DFS payload is not tied to the SMB version we can: * isolate the DFS payload in its own struct, and include that struct in packet structs * move the function that parses the response to misc.c and make it work on the new DFS payload struct (add payload size and utf16 flag as a result). Signed-off-by: Aurelien Aptel <aaptel@suse.com> Acked-by: Pavel Shilovsky <pshilov@microsoft.com> Signed-off-by: Steve French <smfrench@gmail.com>
This commit is contained in:
parent
61cfac6f26
commit
4ecce920e1
|
@ -2086,17 +2086,21 @@ typedef struct dfs_referral_level_3 { /* version 4 is same, + one flag bit */
|
|||
__u8 ServiceSiteGuid[16]; /* MBZ, ignored */
|
||||
} __attribute__((packed)) REFERRAL3;
|
||||
|
||||
typedef struct smb_com_transaction_get_dfs_refer_rsp {
|
||||
struct smb_hdr hdr; /* wct = 10 */
|
||||
struct trans2_resp t2;
|
||||
__u16 ByteCount;
|
||||
__u8 Pad;
|
||||
struct get_dfs_referral_rsp {
|
||||
__le16 PathConsumed;
|
||||
__le16 NumberOfReferrals;
|
||||
__le32 DFSFlags;
|
||||
REFERRAL3 referrals[1]; /* array of level 3 dfs_referral structures */
|
||||
/* followed by the strings pointed to by the referral structures */
|
||||
} __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_RSP;
|
||||
} __packed;
|
||||
|
||||
typedef struct smb_com_transaction_get_dfs_refer_rsp {
|
||||
struct smb_hdr hdr; /* wct = 10 */
|
||||
struct trans2_resp t2;
|
||||
__u16 ByteCount;
|
||||
__u8 Pad;
|
||||
struct get_dfs_referral_rsp dfs_data;
|
||||
} __packed TRANSACTION2_GET_DFS_REFER_RSP;
|
||||
|
||||
/* DFS Flags */
|
||||
#define DFSREF_REFERRAL_SERVER 0x00000001 /* all targets are DFS roots */
|
||||
|
|
|
@ -284,6 +284,11 @@ extern int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,
|
|||
const struct nls_table *nls_codepage,
|
||||
unsigned int *num_referrals,
|
||||
struct dfs_info3_param **referrals, int remap);
|
||||
extern int parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
|
||||
unsigned int *num_of_nodes,
|
||||
struct dfs_info3_param **target_nodes,
|
||||
const struct nls_table *nls_codepage, int remap,
|
||||
const char *searchName, bool is_unicode);
|
||||
extern void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
struct smb_vol *vol);
|
||||
|
|
|
@ -4786,117 +4786,6 @@ CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
return rc;
|
||||
}
|
||||
|
||||
/* parses DFS refferal V3 structure
|
||||
* caller is responsible for freeing target_nodes
|
||||
* returns:
|
||||
* on success - 0
|
||||
* on failure - errno
|
||||
*/
|
||||
static int
|
||||
parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
|
||||
unsigned int *num_of_nodes,
|
||||
struct dfs_info3_param **target_nodes,
|
||||
const struct nls_table *nls_codepage, int remap,
|
||||
const char *searchName)
|
||||
{
|
||||
int i, rc = 0;
|
||||
char *data_end;
|
||||
bool is_unicode;
|
||||
struct dfs_referral_level_3 *ref;
|
||||
|
||||
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
|
||||
is_unicode = true;
|
||||
else
|
||||
is_unicode = false;
|
||||
*num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
|
||||
|
||||
if (*num_of_nodes < 1) {
|
||||
cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
|
||||
*num_of_nodes);
|
||||
rc = -EINVAL;
|
||||
goto parse_DFS_referrals_exit;
|
||||
}
|
||||
|
||||
ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
|
||||
if (ref->VersionNumber != cpu_to_le16(3)) {
|
||||
cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
|
||||
le16_to_cpu(ref->VersionNumber));
|
||||
rc = -EINVAL;
|
||||
goto parse_DFS_referrals_exit;
|
||||
}
|
||||
|
||||
/* get the upper boundary of the resp buffer */
|
||||
data_end = (char *)(&(pSMBr->PathConsumed)) +
|
||||
le16_to_cpu(pSMBr->t2.DataCount);
|
||||
|
||||
cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
|
||||
*num_of_nodes, le32_to_cpu(pSMBr->DFSFlags));
|
||||
|
||||
*target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
|
||||
GFP_KERNEL);
|
||||
if (*target_nodes == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto parse_DFS_referrals_exit;
|
||||
}
|
||||
|
||||
/* collect necessary data from referrals */
|
||||
for (i = 0; i < *num_of_nodes; i++) {
|
||||
char *temp;
|
||||
int max_len;
|
||||
struct dfs_info3_param *node = (*target_nodes)+i;
|
||||
|
||||
node->flags = le32_to_cpu(pSMBr->DFSFlags);
|
||||
if (is_unicode) {
|
||||
__le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
|
||||
GFP_KERNEL);
|
||||
if (tmp == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto parse_DFS_referrals_exit;
|
||||
}
|
||||
cifsConvertToUTF16((__le16 *) tmp, searchName,
|
||||
PATH_MAX, nls_codepage, remap);
|
||||
node->path_consumed = cifs_utf16_bytes(tmp,
|
||||
le16_to_cpu(pSMBr->PathConsumed),
|
||||
nls_codepage);
|
||||
kfree(tmp);
|
||||
} else
|
||||
node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
|
||||
|
||||
node->server_type = le16_to_cpu(ref->ServerType);
|
||||
node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
|
||||
|
||||
/* copy DfsPath */
|
||||
temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
|
||||
max_len = data_end - temp;
|
||||
node->path_name = cifs_strndup_from_utf16(temp, max_len,
|
||||
is_unicode, nls_codepage);
|
||||
if (!node->path_name) {
|
||||
rc = -ENOMEM;
|
||||
goto parse_DFS_referrals_exit;
|
||||
}
|
||||
|
||||
/* copy link target UNC */
|
||||
temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
|
||||
max_len = data_end - temp;
|
||||
node->node_name = cifs_strndup_from_utf16(temp, max_len,
|
||||
is_unicode, nls_codepage);
|
||||
if (!node->node_name) {
|
||||
rc = -ENOMEM;
|
||||
goto parse_DFS_referrals_exit;
|
||||
}
|
||||
|
||||
ref++;
|
||||
}
|
||||
|
||||
parse_DFS_referrals_exit:
|
||||
if (rc) {
|
||||
free_dfs_info_array(*target_nodes, *num_of_nodes);
|
||||
*target_nodes = NULL;
|
||||
*num_of_nodes = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
|
||||
const char *search_name, struct dfs_info3_param **target_nodes,
|
||||
|
@ -4993,9 +4882,11 @@ CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
|
|||
get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
|
||||
|
||||
/* parse returned result into more usable form */
|
||||
rc = parse_DFS_referrals(pSMBr, num_of_nodes,
|
||||
target_nodes, nls_codepage, remap,
|
||||
search_name);
|
||||
rc = parse_dfs_referrals(&pSMBr->dfs_data,
|
||||
le16_to_cpu(pSMBr->t2.DataCount),
|
||||
num_of_nodes, target_nodes, nls_codepage,
|
||||
remap, search_name,
|
||||
pSMBr->hdr.Flags2 & SMBFLG2_UNICODE);
|
||||
|
||||
GetDFSRefExit:
|
||||
cifs_buf_release(pSMB);
|
||||
|
|
105
fs/cifs/misc.c
105
fs/cifs/misc.c
|
@ -640,3 +640,108 @@ cifs_add_pending_open(struct cifs_fid *fid, struct tcon_link *tlink,
|
|||
cifs_add_pending_open_locked(fid, tlink, open);
|
||||
spin_unlock(&tlink_tcon(open->tlink)->open_file_lock);
|
||||
}
|
||||
|
||||
/* parses DFS refferal V3 structure
|
||||
* caller is responsible for freeing target_nodes
|
||||
* returns:
|
||||
* - on success - 0
|
||||
* - on failure - errno
|
||||
*/
|
||||
int
|
||||
parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
|
||||
unsigned int *num_of_nodes,
|
||||
struct dfs_info3_param **target_nodes,
|
||||
const struct nls_table *nls_codepage, int remap,
|
||||
const char *searchName, bool is_unicode)
|
||||
{
|
||||
int i, rc = 0;
|
||||
char *data_end;
|
||||
struct dfs_referral_level_3 *ref;
|
||||
|
||||
*num_of_nodes = le16_to_cpu(rsp->NumberOfReferrals);
|
||||
|
||||
if (*num_of_nodes < 1) {
|
||||
cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
|
||||
*num_of_nodes);
|
||||
rc = -EINVAL;
|
||||
goto parse_DFS_referrals_exit;
|
||||
}
|
||||
|
||||
ref = (struct dfs_referral_level_3 *) &(rsp->referrals);
|
||||
if (ref->VersionNumber != cpu_to_le16(3)) {
|
||||
cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
|
||||
le16_to_cpu(ref->VersionNumber));
|
||||
rc = -EINVAL;
|
||||
goto parse_DFS_referrals_exit;
|
||||
}
|
||||
|
||||
/* get the upper boundary of the resp buffer */
|
||||
data_end = (char *)rsp + rsp_size;
|
||||
|
||||
cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
|
||||
*num_of_nodes, le32_to_cpu(rsp->DFSFlags));
|
||||
|
||||
*target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
|
||||
GFP_KERNEL);
|
||||
if (*target_nodes == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto parse_DFS_referrals_exit;
|
||||
}
|
||||
|
||||
/* collect necessary data from referrals */
|
||||
for (i = 0; i < *num_of_nodes; i++) {
|
||||
char *temp;
|
||||
int max_len;
|
||||
struct dfs_info3_param *node = (*target_nodes)+i;
|
||||
|
||||
node->flags = le32_to_cpu(rsp->DFSFlags);
|
||||
if (is_unicode) {
|
||||
__le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
|
||||
GFP_KERNEL);
|
||||
if (tmp == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto parse_DFS_referrals_exit;
|
||||
}
|
||||
cifsConvertToUTF16((__le16 *) tmp, searchName,
|
||||
PATH_MAX, nls_codepage, remap);
|
||||
node->path_consumed = cifs_utf16_bytes(tmp,
|
||||
le16_to_cpu(rsp->PathConsumed),
|
||||
nls_codepage);
|
||||
kfree(tmp);
|
||||
} else
|
||||
node->path_consumed = le16_to_cpu(rsp->PathConsumed);
|
||||
|
||||
node->server_type = le16_to_cpu(ref->ServerType);
|
||||
node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
|
||||
|
||||
/* copy DfsPath */
|
||||
temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
|
||||
max_len = data_end - temp;
|
||||
node->path_name = cifs_strndup_from_utf16(temp, max_len,
|
||||
is_unicode, nls_codepage);
|
||||
if (!node->path_name) {
|
||||
rc = -ENOMEM;
|
||||
goto parse_DFS_referrals_exit;
|
||||
}
|
||||
|
||||
/* copy link target UNC */
|
||||
temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
|
||||
max_len = data_end - temp;
|
||||
node->node_name = cifs_strndup_from_utf16(temp, max_len,
|
||||
is_unicode, nls_codepage);
|
||||
if (!node->node_name) {
|
||||
rc = -ENOMEM;
|
||||
goto parse_DFS_referrals_exit;
|
||||
}
|
||||
|
||||
ref++;
|
||||
}
|
||||
|
||||
parse_DFS_referrals_exit:
|
||||
if (rc) {
|
||||
free_dfs_info_array(*target_nodes, *num_of_nodes);
|
||||
*target_nodes = NULL;
|
||||
*num_of_nodes = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user