aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/cifssmb.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/cifssmb.c')
-rw-r--r--fs/cifs/cifssmb.c169
1 files changed, 77 insertions, 92 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 9c04ad404553..fc297383cb0e 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -3870,8 +3870,8 @@ GetInodeNumOut:
3870int 3870int
3871CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, 3871CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3872 const unsigned char *searchName, 3872 const unsigned char *searchName,
3873 unsigned char **targetUNCs, 3873 struct dfs_info3_param **target_nodes,
3874 unsigned int *number_of_UNC_in_array, 3874 unsigned int *num_of_nodes,
3875 const struct nls_table *nls_codepage, int remap) 3875 const struct nls_table *nls_codepage, int remap)
3876{ 3876{
3877/* TRANS2_GET_DFS_REFERRAL */ 3877/* TRANS2_GET_DFS_REFERRAL */
@@ -3884,8 +3884,8 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3884 unsigned int i; 3884 unsigned int i;
3885 char *temp; 3885 char *temp;
3886 __u16 params, byte_count; 3886 __u16 params, byte_count;
3887 *number_of_UNC_in_array = 0; 3887 *num_of_nodes = 0;
3888 *targetUNCs = NULL; 3888 *target_nodes = NULL;
3889 3889
3890 cFYI(1, ("In GetDFSRefer the path %s", searchName)); 3890 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3891 if (ses == NULL) 3891 if (ses == NULL)
@@ -3955,99 +3955,84 @@ getDFSRetry:
3955 (struct smb_hdr *) pSMBr, &bytes_returned, 0); 3955 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3956 if (rc) { 3956 if (rc) {
3957 cFYI(1, ("Send error in GetDFSRefer = %d", rc)); 3957 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3958 } else { /* decode response */ 3958 goto GetDFSRefExit;
3959/* BB Add logic to parse referrals here */ 3959 }
3960 rc = validate_t2((struct smb_t2_rsp *)pSMBr); 3960 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3961
3962 /* BB Also check if enough total bytes returned? */
3963 if (rc || (pSMBr->ByteCount < 17))
3964 rc = -EIO; /* bad smb */
3965 else {
3966 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3967 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3968
3969 cFYI(1,
3970 ("Decoding GetDFSRefer response BCC: %d Offset %d",
3971 pSMBr->ByteCount, data_offset));
3972 referrals =
3973 (struct dfs_referral_level_3 *)
3974 (8 /* sizeof start of data block */ +
3975 data_offset +
3976 (char *) &pSMBr->hdr.Protocol);
3977 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
3978 "for referral one refer size: 0x%x srv "
3979 "type: 0x%x refer flags: 0x%x ttl: 0x%x",
3980 le16_to_cpu(pSMBr->NumberOfReferrals),
3981 le16_to_cpu(pSMBr->DFSFlags),
3982 le16_to_cpu(referrals->ReferralSize),
3983 le16_to_cpu(referrals->ServerType),
3984 le16_to_cpu(referrals->ReferralFlags),
3985 le16_to_cpu(referrals->TimeToLive)));
3986 /* BB This field is actually two bytes in from start of
3987 data block so we could do safety check that DataBlock
3988 begins at address of pSMBr->NumberOfReferrals */
3989 *number_of_UNC_in_array =
3990 le16_to_cpu(pSMBr->NumberOfReferrals);
3991
3992 /* BB Fix below so can return more than one referral */
3993 if (*number_of_UNC_in_array > 1)
3994 *number_of_UNC_in_array = 1;
3995
3996 /* get the length of the strings describing refs */
3997 name_len = 0;
3998 for (i = 0; i < *number_of_UNC_in_array; i++) {
3999 /* make sure that DfsPathOffset not past end */
4000 __u16 offset =
4001 le16_to_cpu(referrals->DfsPathOffset);
4002 if (offset > data_count) {
4003 /* if invalid referral, stop here and do
4004 not try to copy any more */
4005 *number_of_UNC_in_array = i;
4006 break;
4007 }
4008 temp = ((char *)referrals) + offset;
4009 3961
4010 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { 3962 /* BB Also check if enough total bytes returned? */
4011 name_len += UniStrnlen((wchar_t *)temp, 3963 if (rc || (pSMBr->ByteCount < 17))
4012 data_count); 3964 rc = -EIO; /* bad smb */
4013 } else { 3965 else {
4014 name_len += strnlen(temp, data_count); 3966 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4015 } 3967 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
4016 referrals++; 3968
4017 /* BB add check that referral pointer does 3969 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4018 not fall off end PDU */ 3970 pSMBr->ByteCount, data_offset));
4019 } 3971 referrals =
4020 /* BB add check for name_len bigger than bcc */ 3972 (struct dfs_referral_level_3 *)
4021 *targetUNCs = 3973 (8 /* sizeof start of data block */ +
4022 kmalloc(name_len+1+(*number_of_UNC_in_array), 3974 data_offset +
4023 GFP_KERNEL); 3975 (char *) &pSMBr->hdr.Protocol);
4024 if (*targetUNCs == NULL) { 3976 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
4025 rc = -ENOMEM; 3977 "for referral one refer size: 0x%x srv "
4026 goto GetDFSRefExit; 3978 "type: 0x%x refer flags: 0x%x ttl: 0x%x",
3979 le16_to_cpu(pSMBr->NumberOfReferrals),
3980 le16_to_cpu(pSMBr->DFSFlags),
3981 le16_to_cpu(referrals->ReferralSize),
3982 le16_to_cpu(referrals->ServerType),
3983 le16_to_cpu(referrals->ReferralFlags),
3984 le16_to_cpu(referrals->TimeToLive)));
3985 /* BB This field is actually two bytes in from start of
3986 data block so we could do safety check that DataBlock
3987 begins at address of pSMBr->NumberOfReferrals */
3988 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3989
3990 /* BB Fix below so can return more than one referral */
3991 if (*num_of_nodes > 1)
3992 *num_of_nodes = 1;
3993
3994 /* get the length of the strings describing refs */
3995 name_len = 0;
3996 for (i = 0; i < *num_of_nodes; i++) {
3997 /* make sure that DfsPathOffset not past end */
3998 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3999 if (offset > data_count) {
4000 /* if invalid referral, stop here and do
4001 not try to copy any more */
4002 *num_of_nodes = i;
4003 break;
4027 } 4004 }
4028 /* copy the ref strings */ 4005 temp = ((char *)referrals) + offset;
4029 referrals = (struct dfs_referral_level_3 *) 4006
4030 (8 /* sizeof data hdr */ + data_offset + 4007 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4031 (char *) &pSMBr->hdr.Protocol); 4008 name_len += UniStrnlen((wchar_t *)temp,
4032 4009 data_count);
4033 for (i = 0; i < *number_of_UNC_in_array; i++) { 4010 } else {
4034 temp = ((char *)referrals) + 4011 name_len += strnlen(temp, data_count);
4035 le16_to_cpu(referrals->DfsPathOffset);
4036 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4037 cifs_strfromUCS_le(*targetUNCs,
4038 (__le16 *) temp,
4039 name_len,
4040 nls_codepage);
4041 } else {
4042 strncpy(*targetUNCs, temp, name_len);
4043 }
4044 /* BB update target_uncs pointers */
4045 referrals++;
4046 } 4012 }
4047 temp = *targetUNCs; 4013 referrals++;
4048 temp[name_len] = 0; 4014 /* BB add check that referral pointer does
4015 not fall off end PDU */
4016 }
4017 /* BB add check for name_len bigger than bcc */
4018 *target_nodes =
4019 kmalloc(name_len+1+(*num_of_nodes),
4020 GFP_KERNEL);
4021 if (*target_nodes == NULL) {
4022 rc = -ENOMEM;
4023 goto GetDFSRefExit;
4049 } 4024 }
4050 4025
4026 referrals = (struct dfs_referral_level_3 *)
4027 (8 /* sizeof data hdr */ + data_offset +
4028 (char *) &pSMBr->hdr.Protocol);
4029
4030 for (i = 0; i < *num_of_nodes; i++) {
4031 temp = ((char *)referrals) +
4032 le16_to_cpu(referrals->DfsPathOffset);
4033 /* BB update target_uncs pointers */
4034 referrals++;
4035 }
4051 } 4036 }
4052GetDFSRefExit: 4037GetDFSRefExit:
4053 if (pSMB) 4038 if (pSMB)