diff options
Diffstat (limited to 'fs/cifs/cifssmb.c')
-rw-r--r-- | fs/cifs/cifssmb.c | 169 |
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: | |||
3870 | int | 3870 | int |
3871 | CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, | 3871 | CIFSGetDFSRefer(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 | } |
4052 | GetDFSRefExit: | 4037 | GetDFSRefExit: |
4053 | if (pSMB) | 4038 | if (pSMB) |