diff options
Diffstat (limited to 'fs/cifs/cifssmb.c')
-rw-r--r-- | fs/cifs/cifssmb.c | 111 |
1 files changed, 51 insertions, 60 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index a89c4cb4e6cf..4baf35949b51 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -463,7 +463,6 @@ decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr) | |||
463 | cifs_max_pending); | 463 | cifs_max_pending); |
464 | set_credits(server, server->maxReq); | 464 | set_credits(server, server->maxReq); |
465 | server->maxBuf = le16_to_cpu(rsp->MaxBufSize); | 465 | server->maxBuf = le16_to_cpu(rsp->MaxBufSize); |
466 | server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); | ||
467 | /* even though we do not use raw we might as well set this | 466 | /* even though we do not use raw we might as well set this |
468 | accurately, in case we ever find a need for it */ | 467 | accurately, in case we ever find a need for it */ |
469 | if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { | 468 | if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { |
@@ -3067,7 +3066,6 @@ querySymLinkRetry: | |||
3067 | return rc; | 3066 | return rc; |
3068 | } | 3067 | } |
3069 | 3068 | ||
3070 | #ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL | ||
3071 | /* | 3069 | /* |
3072 | * Recent Windows versions now create symlinks more frequently | 3070 | * Recent Windows versions now create symlinks more frequently |
3073 | * and they use the "reparse point" mechanism below. We can of course | 3071 | * and they use the "reparse point" mechanism below. We can of course |
@@ -3079,18 +3077,22 @@ querySymLinkRetry: | |||
3079 | * it is not compiled in by default until callers fixed up and more tested. | 3077 | * it is not compiled in by default until callers fixed up and more tested. |
3080 | */ | 3078 | */ |
3081 | int | 3079 | int |
3082 | CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon, | 3080 | CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, |
3083 | const unsigned char *searchName, | 3081 | __u16 fid, char **symlinkinfo, |
3084 | char *symlinkinfo, const int buflen, __u16 fid, | 3082 | const struct nls_table *nls_codepage) |
3085 | const struct nls_table *nls_codepage) | ||
3086 | { | 3083 | { |
3087 | int rc = 0; | 3084 | int rc = 0; |
3088 | int bytes_returned; | 3085 | int bytes_returned; |
3089 | struct smb_com_transaction_ioctl_req *pSMB; | 3086 | struct smb_com_transaction_ioctl_req *pSMB; |
3090 | struct smb_com_transaction_ioctl_rsp *pSMBr; | 3087 | struct smb_com_transaction_ioctl_rsp *pSMBr; |
3088 | bool is_unicode; | ||
3089 | unsigned int sub_len; | ||
3090 | char *sub_start; | ||
3091 | struct reparse_data *reparse_buf; | ||
3092 | __u32 data_offset, data_count; | ||
3093 | char *end_of_smb; | ||
3091 | 3094 | ||
3092 | cifs_dbg(FYI, "In Windows reparse style QueryLink for path %s\n", | 3095 | cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid); |
3093 | searchName); | ||
3094 | rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, | 3096 | rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, |
3095 | (void **) &pSMBr); | 3097 | (void **) &pSMBr); |
3096 | if (rc) | 3098 | if (rc) |
@@ -3119,66 +3121,55 @@ CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon, | |||
3119 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 3121 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
3120 | if (rc) { | 3122 | if (rc) { |
3121 | cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc); | 3123 | cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc); |
3122 | } else { /* decode response */ | 3124 | goto qreparse_out; |
3123 | __u32 data_offset = le32_to_cpu(pSMBr->DataOffset); | 3125 | } |
3124 | __u32 data_count = le32_to_cpu(pSMBr->DataCount); | ||
3125 | if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) { | ||
3126 | /* BB also check enough total bytes returned */ | ||
3127 | rc = -EIO; /* bad smb */ | ||
3128 | goto qreparse_out; | ||
3129 | } | ||
3130 | if (data_count && (data_count < 2048)) { | ||
3131 | char *end_of_smb = 2 /* sizeof byte count */ + | ||
3132 | get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount; | ||
3133 | |||
3134 | struct reparse_data *reparse_buf = | ||
3135 | (struct reparse_data *) | ||
3136 | ((char *)&pSMBr->hdr.Protocol | ||
3137 | + data_offset); | ||
3138 | if ((char *)reparse_buf >= end_of_smb) { | ||
3139 | rc = -EIO; | ||
3140 | goto qreparse_out; | ||
3141 | } | ||
3142 | if ((reparse_buf->LinkNamesBuf + | ||
3143 | reparse_buf->TargetNameOffset + | ||
3144 | reparse_buf->TargetNameLen) > end_of_smb) { | ||
3145 | cifs_dbg(FYI, "reparse buf beyond SMB\n"); | ||
3146 | rc = -EIO; | ||
3147 | goto qreparse_out; | ||
3148 | } | ||
3149 | 3126 | ||
3150 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { | 3127 | data_offset = le32_to_cpu(pSMBr->DataOffset); |
3151 | cifs_from_ucs2(symlinkinfo, (__le16 *) | 3128 | data_count = le32_to_cpu(pSMBr->DataCount); |
3152 | (reparse_buf->LinkNamesBuf + | 3129 | if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) { |
3153 | reparse_buf->TargetNameOffset), | 3130 | /* BB also check enough total bytes returned */ |
3154 | buflen, | 3131 | rc = -EIO; /* bad smb */ |
3155 | reparse_buf->TargetNameLen, | 3132 | goto qreparse_out; |
3156 | nls_codepage, 0); | 3133 | } |
3157 | } else { /* ASCII names */ | 3134 | if (!data_count || (data_count > 2048)) { |
3158 | strncpy(symlinkinfo, | 3135 | rc = -EIO; |
3159 | reparse_buf->LinkNamesBuf + | 3136 | cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n"); |
3160 | reparse_buf->TargetNameOffset, | 3137 | goto qreparse_out; |
3161 | min_t(const int, buflen, | 3138 | } |
3162 | reparse_buf->TargetNameLen)); | 3139 | end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount; |
3163 | } | 3140 | reparse_buf = (struct reparse_data *) |
3164 | } else { | 3141 | ((char *)&pSMBr->hdr.Protocol + data_offset); |
3165 | rc = -EIO; | 3142 | if ((char *)reparse_buf >= end_of_smb) { |
3166 | cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n"); | 3143 | rc = -EIO; |
3167 | } | 3144 | goto qreparse_out; |
3168 | symlinkinfo[buflen] = 0; /* just in case so the caller | ||
3169 | does not go off the end of the buffer */ | ||
3170 | cifs_dbg(FYI, "readlink result - %s\n", symlinkinfo); | ||
3171 | } | 3145 | } |
3146 | if ((reparse_buf->PathBuffer + reparse_buf->PrintNameOffset + | ||
3147 | reparse_buf->PrintNameLength) > end_of_smb) { | ||
3148 | cifs_dbg(FYI, "reparse buf beyond SMB\n"); | ||
3149 | rc = -EIO; | ||
3150 | goto qreparse_out; | ||
3151 | } | ||
3152 | sub_start = reparse_buf->SubstituteNameOffset + reparse_buf->PathBuffer; | ||
3153 | sub_len = reparse_buf->SubstituteNameLength; | ||
3154 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) | ||
3155 | is_unicode = true; | ||
3156 | else | ||
3157 | is_unicode = false; | ||
3172 | 3158 | ||
3159 | /* BB FIXME investigate remapping reserved chars here */ | ||
3160 | *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode, | ||
3161 | nls_codepage); | ||
3162 | if (!*symlinkinfo) | ||
3163 | rc = -ENOMEM; | ||
3173 | qreparse_out: | 3164 | qreparse_out: |
3174 | cifs_buf_release(pSMB); | 3165 | cifs_buf_release(pSMB); |
3175 | 3166 | ||
3176 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 3167 | /* |
3177 | since file handle passed in no longer valid */ | 3168 | * Note: On -EAGAIN error only caller can retry on handle based calls |
3178 | 3169 | * since file handle passed in no longer valid. | |
3170 | */ | ||
3179 | return rc; | 3171 | return rc; |
3180 | } | 3172 | } |
3181 | #endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */ | ||
3182 | 3173 | ||
3183 | #ifdef CONFIG_CIFS_POSIX | 3174 | #ifdef CONFIG_CIFS_POSIX |
3184 | 3175 | ||