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.c497
1 files changed, 261 insertions, 236 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 941441d3e386..7cc7f83e9314 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -170,19 +170,19 @@ cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
170 * need to prevent multiple threads trying to simultaneously 170 * need to prevent multiple threads trying to simultaneously
171 * reconnect the same SMB session 171 * reconnect the same SMB session
172 */ 172 */
173 down(&ses->sesSem); 173 mutex_lock(&ses->session_mutex);
174 if (ses->need_reconnect) 174 if (ses->need_reconnect)
175 rc = cifs_setup_session(0, ses, nls_codepage); 175 rc = cifs_setup_session(0, ses, nls_codepage);
176 176
177 /* do we need to reconnect tcon? */ 177 /* do we need to reconnect tcon? */
178 if (rc || !tcon->need_reconnect) { 178 if (rc || !tcon->need_reconnect) {
179 up(&ses->sesSem); 179 mutex_unlock(&ses->session_mutex);
180 goto out; 180 goto out;
181 } 181 }
182 182
183 mark_open_files_invalid(tcon); 183 mark_open_files_invalid(tcon);
184 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage); 184 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
185 up(&ses->sesSem); 185 mutex_unlock(&ses->session_mutex);
186 cFYI(1, ("reconnect tcon rc = %d", rc)); 186 cFYI(1, ("reconnect tcon rc = %d", rc));
187 187
188 if (rc) 188 if (rc)
@@ -500,7 +500,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
500 } else if (pSMBr->hdr.WordCount == 13) { 500 } else if (pSMBr->hdr.WordCount == 13) {
501 cERROR(1, ("mount failed, cifs module not built " 501 cERROR(1, ("mount failed, cifs module not built "
502 "with CIFS_WEAK_PW_HASH support")); 502 "with CIFS_WEAK_PW_HASH support"));
503 rc = -EOPNOTSUPP; 503 rc = -EOPNOTSUPP;
504#endif /* WEAK_PW_HASH */ 504#endif /* WEAK_PW_HASH */
505 goto neg_err_exit; 505 goto neg_err_exit;
506 } else if (pSMBr->hdr.WordCount != 17) { 506 } else if (pSMBr->hdr.WordCount != 17) {
@@ -700,13 +700,13 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
700 if (!ses || !ses->server) 700 if (!ses || !ses->server)
701 return -EIO; 701 return -EIO;
702 702
703 down(&ses->sesSem); 703 mutex_lock(&ses->session_mutex);
704 if (ses->need_reconnect) 704 if (ses->need_reconnect)
705 goto session_already_dead; /* no need to send SMBlogoff if uid 705 goto session_already_dead; /* no need to send SMBlogoff if uid
706 already closed due to reconnect */ 706 already closed due to reconnect */
707 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB); 707 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
708 if (rc) { 708 if (rc) {
709 up(&ses->sesSem); 709 mutex_unlock(&ses->session_mutex);
710 return rc; 710 return rc;
711 } 711 }
712 712
@@ -721,7 +721,7 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
721 pSMB->AndXCommand = 0xFF; 721 pSMB->AndXCommand = 0xFF;
722 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0); 722 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
723session_already_dead: 723session_already_dead:
724 up(&ses->sesSem); 724 mutex_unlock(&ses->session_mutex);
725 725
726 /* if session dead then we do not need to do ulogoff, 726 /* if session dead then we do not need to do ulogoff,
727 since server closed smb session, no sense reporting 727 since server closed smb session, no sense reporting
@@ -3230,8 +3230,72 @@ QInfRetry:
3230 return rc; 3230 return rc;
3231} 3231}
3232 3232
3233int
3234CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
3235 u16 netfid, FILE_ALL_INFO *pFindData)
3236{
3237 struct smb_t2_qfi_req *pSMB = NULL;
3238 struct smb_t2_qfi_rsp *pSMBr = NULL;
3239 int rc = 0;
3240 int bytes_returned;
3241 __u16 params, byte_count;
3242
3243QFileInfoRetry:
3244 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3245 (void **) &pSMBr);
3246 if (rc)
3247 return rc;
3248
3249 params = 2 /* level */ + 2 /* fid */;
3250 pSMB->t2.TotalDataCount = 0;
3251 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3252 /* BB find exact max data count below from sess structure BB */
3253 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3254 pSMB->t2.MaxSetupCount = 0;
3255 pSMB->t2.Reserved = 0;
3256 pSMB->t2.Flags = 0;
3257 pSMB->t2.Timeout = 0;
3258 pSMB->t2.Reserved2 = 0;
3259 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3260 Fid) - 4);
3261 pSMB->t2.DataCount = 0;
3262 pSMB->t2.DataOffset = 0;
3263 pSMB->t2.SetupCount = 1;
3264 pSMB->t2.Reserved3 = 0;
3265 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3266 byte_count = params + 1 /* pad */ ;
3267 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3268 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3269 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3270 pSMB->Pad = 0;
3271 pSMB->Fid = netfid;
3272 pSMB->hdr.smb_buf_length += byte_count;
3273
3274 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3275 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3276 if (rc) {
3277 cFYI(1, ("Send error in QPathInfo = %d", rc));
3278 } else { /* decode response */
3279 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3233 3280
3281 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3282 rc = -EIO;
3283 else if (pSMBr->ByteCount < 40)
3284 rc = -EIO; /* bad smb */
3285 else if (pFindData) {
3286 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3287 memcpy((char *) pFindData,
3288 (char *) &pSMBr->hdr.Protocol +
3289 data_offset, sizeof(FILE_ALL_INFO));
3290 } else
3291 rc = -ENOMEM;
3292 }
3293 cifs_buf_release(pSMB);
3294 if (rc == -EAGAIN)
3295 goto QFileInfoRetry;
3234 3296
3297 return rc;
3298}
3235 3299
3236int 3300int
3237CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, 3301CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
@@ -3335,6 +3399,75 @@ QPathInfoRetry:
3335} 3399}
3336 3400
3337int 3401int
3402CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
3403 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3404{
3405 struct smb_t2_qfi_req *pSMB = NULL;
3406 struct smb_t2_qfi_rsp *pSMBr = NULL;
3407 int rc = 0;
3408 int bytes_returned;
3409 __u16 params, byte_count;
3410
3411UnixQFileInfoRetry:
3412 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3413 (void **) &pSMBr);
3414 if (rc)
3415 return rc;
3416
3417 params = 2 /* level */ + 2 /* fid */;
3418 pSMB->t2.TotalDataCount = 0;
3419 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3420 /* BB find exact max data count below from sess structure BB */
3421 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3422 pSMB->t2.MaxSetupCount = 0;
3423 pSMB->t2.Reserved = 0;
3424 pSMB->t2.Flags = 0;
3425 pSMB->t2.Timeout = 0;
3426 pSMB->t2.Reserved2 = 0;
3427 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3428 Fid) - 4);
3429 pSMB->t2.DataCount = 0;
3430 pSMB->t2.DataOffset = 0;
3431 pSMB->t2.SetupCount = 1;
3432 pSMB->t2.Reserved3 = 0;
3433 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3434 byte_count = params + 1 /* pad */ ;
3435 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3436 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3437 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3438 pSMB->Pad = 0;
3439 pSMB->Fid = netfid;
3440 pSMB->hdr.smb_buf_length += byte_count;
3441
3442 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3443 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3444 if (rc) {
3445 cFYI(1, ("Send error in QPathInfo = %d", rc));
3446 } else { /* decode response */
3447 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3448
3449 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3450 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3451 "Unix Extensions can be disabled on mount "
3452 "by specifying the nosfu mount option."));
3453 rc = -EIO; /* bad smb */
3454 } else {
3455 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3456 memcpy((char *) pFindData,
3457 (char *) &pSMBr->hdr.Protocol +
3458 data_offset,
3459 sizeof(FILE_UNIX_BASIC_INFO));
3460 }
3461 }
3462
3463 cifs_buf_release(pSMB);
3464 if (rc == -EAGAIN)
3465 goto UnixQFileInfoRetry;
3466
3467 return rc;
3468}
3469
3470int
3338CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon, 3471CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3339 const unsigned char *searchName, 3472 const unsigned char *searchName,
3340 FILE_UNIX_BASIC_INFO *pFindData, 3473 FILE_UNIX_BASIC_INFO *pFindData,
@@ -3886,7 +4019,7 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
3886 goto parse_DFS_referrals_exit; 4019 goto parse_DFS_referrals_exit;
3887 } 4020 }
3888 4021
3889 /* collect neccessary data from referrals */ 4022 /* collect necessary data from referrals */
3890 for (i = 0; i < *num_of_nodes; i++) { 4023 for (i = 0; i < *num_of_nodes; i++) {
3891 char *temp; 4024 char *temp;
3892 int max_len; 4025 int max_len;
@@ -5269,22 +5402,34 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5269 cifs_buf_release(pSMB); 5402 cifs_buf_release(pSMB);
5270 return rc; 5403 return rc;
5271} 5404}
5405
5272#ifdef CONFIG_CIFS_XATTR 5406#ifdef CONFIG_CIFS_XATTR
5407/*
5408 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5409 * function used by listxattr and getxattr type calls. When ea_name is set,
5410 * it looks for that attribute name and stuffs that value into the EAData
5411 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5412 * buffer. In both cases, the return value is either the length of the
5413 * resulting data or a negative error code. If EAData is a NULL pointer then
5414 * the data isn't copied to it, but the length is returned.
5415 */
5273ssize_t 5416ssize_t
5274CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, 5417CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5275 const unsigned char *searchName, 5418 const unsigned char *searchName, const unsigned char *ea_name,
5276 char *EAData, size_t buf_size, 5419 char *EAData, size_t buf_size,
5277 const struct nls_table *nls_codepage, int remap) 5420 const struct nls_table *nls_codepage, int remap)
5278{ 5421{
5279 /* BB assumes one setup word */ 5422 /* BB assumes one setup word */
5280 TRANSACTION2_QPI_REQ *pSMB = NULL; 5423 TRANSACTION2_QPI_REQ *pSMB = NULL;
5281 TRANSACTION2_QPI_RSP *pSMBr = NULL; 5424 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5282 int rc = 0; 5425 int rc = 0;
5283 int bytes_returned; 5426 int bytes_returned;
5284 int name_len; 5427 int list_len;
5428 struct fealist *ea_response_data;
5285 struct fea *temp_fea; 5429 struct fea *temp_fea;
5286 char *temp_ptr; 5430 char *temp_ptr;
5287 __u16 params, byte_count; 5431 char *end_of_smb;
5432 __u16 params, byte_count, data_offset;
5288 5433
5289 cFYI(1, ("In Query All EAs path %s", searchName)); 5434 cFYI(1, ("In Query All EAs path %s", searchName));
5290QAllEAsRetry: 5435QAllEAsRetry:
@@ -5294,22 +5439,22 @@ QAllEAsRetry:
5294 return rc; 5439 return rc;
5295 5440
5296 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 5441 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5297 name_len = 5442 list_len =
5298 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 5443 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5299 PATH_MAX, nls_codepage, remap); 5444 PATH_MAX, nls_codepage, remap);
5300 name_len++; /* trailing null */ 5445 list_len++; /* trailing null */
5301 name_len *= 2; 5446 list_len *= 2;
5302 } else { /* BB improve the check for buffer overruns BB */ 5447 } else { /* BB improve the check for buffer overruns BB */
5303 name_len = strnlen(searchName, PATH_MAX); 5448 list_len = strnlen(searchName, PATH_MAX);
5304 name_len++; /* trailing null */ 5449 list_len++; /* trailing null */
5305 strncpy(pSMB->FileName, searchName, name_len); 5450 strncpy(pSMB->FileName, searchName, list_len);
5306 } 5451 }
5307 5452
5308 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; 5453 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
5309 pSMB->TotalDataCount = 0; 5454 pSMB->TotalDataCount = 0;
5310 pSMB->MaxParameterCount = cpu_to_le16(2); 5455 pSMB->MaxParameterCount = cpu_to_le16(2);
5311 /* BB find exact max SMB PDU from sess structure BB */ 5456 /* BB find exact max SMB PDU from sess structure BB */
5312 pSMB->MaxDataCount = cpu_to_le16(4000); 5457 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
5313 pSMB->MaxSetupCount = 0; 5458 pSMB->MaxSetupCount = 0;
5314 pSMB->Reserved = 0; 5459 pSMB->Reserved = 0;
5315 pSMB->Flags = 0; 5460 pSMB->Flags = 0;
@@ -5334,237 +5479,117 @@ QAllEAsRetry:
5334 (struct smb_hdr *) pSMBr, &bytes_returned, 0); 5479 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5335 if (rc) { 5480 if (rc) {
5336 cFYI(1, ("Send error in QueryAllEAs = %d", rc)); 5481 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5337 } else { /* decode response */ 5482 goto QAllEAsOut;
5338 rc = validate_t2((struct smb_t2_rsp *)pSMBr); 5483 }
5339 5484
5340 /* BB also check enough total bytes returned */ 5485
5341 /* BB we need to improve the validity checking 5486 /* BB also check enough total bytes returned */
5342 of these trans2 responses */ 5487 /* BB we need to improve the validity checking
5343 if (rc || (pSMBr->ByteCount < 4)) 5488 of these trans2 responses */
5344 rc = -EIO; /* bad smb */ 5489
5345 /* else if (pFindData){ 5490 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5346 memcpy((char *) pFindData, 5491 if (rc || (pSMBr->ByteCount < 4)) {
5347 (char *) &pSMBr->hdr.Protocol + 5492 rc = -EIO; /* bad smb */
5348 data_offset, kl); 5493 goto QAllEAsOut;
5349 }*/ else {
5350 /* check that length of list is not more than bcc */
5351 /* check that each entry does not go beyond length
5352 of list */
5353 /* check that each element of each entry does not
5354 go beyond end of list */
5355 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5356 struct fealist *ea_response_data;
5357 rc = 0;
5358 /* validate_trans2_offsets() */
5359 /* BB check if start of smb + data_offset > &bcc+ bcc */
5360 ea_response_data = (struct fealist *)
5361 (((char *) &pSMBr->hdr.Protocol) +
5362 data_offset);
5363 name_len = le32_to_cpu(ea_response_data->list_len);
5364 cFYI(1, ("ea length %d", name_len));
5365 if (name_len <= 8) {
5366 /* returned EA size zeroed at top of function */
5367 cFYI(1, ("empty EA list returned from server"));
5368 } else {
5369 /* account for ea list len */
5370 name_len -= 4;
5371 temp_fea = ea_response_data->list;
5372 temp_ptr = (char *)temp_fea;
5373 while (name_len > 0) {
5374 __u16 value_len;
5375 name_len -= 4;
5376 temp_ptr += 4;
5377 rc += temp_fea->name_len;
5378 /* account for prefix user. and trailing null */
5379 rc = rc + 5 + 1;
5380 if (rc < (int)buf_size) {
5381 memcpy(EAData, "user.", 5);
5382 EAData += 5;
5383 memcpy(EAData, temp_ptr,
5384 temp_fea->name_len);
5385 EAData += temp_fea->name_len;
5386 /* null terminate name */
5387 *EAData = 0;
5388 EAData = EAData + 1;
5389 } else if (buf_size == 0) {
5390 /* skip copy - calc size only */
5391 } else {
5392 /* stop before overrun buffer */
5393 rc = -ERANGE;
5394 break;
5395 }
5396 name_len -= temp_fea->name_len;
5397 temp_ptr += temp_fea->name_len;
5398 /* account for trailing null */
5399 name_len--;
5400 temp_ptr++;
5401 value_len =
5402 le16_to_cpu(temp_fea->value_len);
5403 name_len -= value_len;
5404 temp_ptr += value_len;
5405 /* BB check that temp_ptr is still
5406 within the SMB BB*/
5407
5408 /* no trailing null to account for
5409 in value len */
5410 /* go on to next EA */
5411 temp_fea = (struct fea *)temp_ptr;
5412 }
5413 }
5414 }
5415 } 5494 }
5416 cifs_buf_release(pSMB);
5417 if (rc == -EAGAIN)
5418 goto QAllEAsRetry;
5419 5495
5420 return (ssize_t)rc; 5496 /* check that length of list is not more than bcc */
5421} 5497 /* check that each entry does not go beyond length
5498 of list */
5499 /* check that each element of each entry does not
5500 go beyond end of list */
5501 /* validate_trans2_offsets() */
5502 /* BB check if start of smb + data_offset > &bcc+ bcc */
5422 5503
5423ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon, 5504 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5424 const unsigned char *searchName, const unsigned char *ea_name, 5505 ea_response_data = (struct fealist *)
5425 unsigned char *ea_value, size_t buf_size, 5506 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5426 const struct nls_table *nls_codepage, int remap)
5427{
5428 TRANSACTION2_QPI_REQ *pSMB = NULL;
5429 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5430 int rc = 0;
5431 int bytes_returned;
5432 int name_len;
5433 struct fea *temp_fea;
5434 char *temp_ptr;
5435 __u16 params, byte_count;
5436 5507
5437 cFYI(1, ("In Query EA path %s", searchName)); 5508 list_len = le32_to_cpu(ea_response_data->list_len);
5438QEARetry: 5509 cFYI(1, ("ea length %d", list_len));
5439 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, 5510 if (list_len <= 8) {
5440 (void **) &pSMBr); 5511 cFYI(1, ("empty EA list returned from server"));
5441 if (rc) 5512 goto QAllEAsOut;
5442 return rc; 5513 }
5443 5514
5444 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 5515 /* make sure list_len doesn't go past end of SMB */
5445 name_len = 5516 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr);
5446 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 5517 if ((char *)ea_response_data + list_len > end_of_smb) {
5447 PATH_MAX, nls_codepage, remap); 5518 cFYI(1, ("EA list appears to go beyond SMB"));
5448 name_len++; /* trailing null */ 5519 rc = -EIO;
5449 name_len *= 2; 5520 goto QAllEAsOut;
5450 } else { /* BB improve the check for buffer overruns BB */
5451 name_len = strnlen(searchName, PATH_MAX);
5452 name_len++; /* trailing null */
5453 strncpy(pSMB->FileName, searchName, name_len);
5454 } 5521 }
5455 5522
5456 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */; 5523 /* account for ea list len */
5457 pSMB->TotalDataCount = 0; 5524 list_len -= 4;
5458 pSMB->MaxParameterCount = cpu_to_le16(2); 5525 temp_fea = ea_response_data->list;
5459 /* BB find exact max SMB PDU from sess structure BB */ 5526 temp_ptr = (char *)temp_fea;
5460 pSMB->MaxDataCount = cpu_to_le16(4000); 5527 while (list_len > 0) {
5461 pSMB->MaxSetupCount = 0; 5528 unsigned int name_len;
5462 pSMB->Reserved = 0; 5529 __u16 value_len;
5463 pSMB->Flags = 0; 5530
5464 pSMB->Timeout = 0; 5531 list_len -= 4;
5465 pSMB->Reserved2 = 0; 5532 temp_ptr += 4;
5466 pSMB->ParameterOffset = cpu_to_le16(offsetof( 5533 /* make sure we can read name_len and value_len */
5467 struct smb_com_transaction2_qpi_req, InformationLevel) - 4); 5534 if (list_len < 0) {
5468 pSMB->DataCount = 0; 5535 cFYI(1, ("EA entry goes beyond length of list"));
5469 pSMB->DataOffset = 0; 5536 rc = -EIO;
5470 pSMB->SetupCount = 1; 5537 goto QAllEAsOut;
5471 pSMB->Reserved3 = 0; 5538 }
5472 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5473 byte_count = params + 1 /* pad */ ;
5474 pSMB->TotalParameterCount = cpu_to_le16(params);
5475 pSMB->ParameterCount = pSMB->TotalParameterCount;
5476 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5477 pSMB->Reserved4 = 0;
5478 pSMB->hdr.smb_buf_length += byte_count;
5479 pSMB->ByteCount = cpu_to_le16(byte_count);
5480 5539
5481 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 5540 name_len = temp_fea->name_len;
5482 (struct smb_hdr *) pSMBr, &bytes_returned, 0); 5541 value_len = le16_to_cpu(temp_fea->value_len);
5483 if (rc) { 5542 list_len -= name_len + 1 + value_len;
5484 cFYI(1, ("Send error in Query EA = %d", rc)); 5543 if (list_len < 0) {
5485 } else { /* decode response */ 5544 cFYI(1, ("EA entry goes beyond length of list"));
5486 rc = validate_t2((struct smb_t2_rsp *)pSMBr); 5545 rc = -EIO;
5546 goto QAllEAsOut;
5547 }
5487 5548
5488 /* BB also check enough total bytes returned */ 5549 if (ea_name) {
5489 /* BB we need to improve the validity checking 5550 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5490 of these trans2 responses */ 5551 temp_ptr += name_len + 1;
5491 if (rc || (pSMBr->ByteCount < 4)) 5552 rc = value_len;
5492 rc = -EIO; /* bad smb */ 5553 if (buf_size == 0)
5493 /* else if (pFindData){ 5554 goto QAllEAsOut;
5494 memcpy((char *) pFindData, 5555 if ((size_t)value_len > buf_size) {
5495 (char *) &pSMBr->hdr.Protocol + 5556 rc = -ERANGE;
5496 data_offset, kl); 5557 goto QAllEAsOut;
5497 }*/ else {
5498 /* check that length of list is not more than bcc */
5499 /* check that each entry does not go beyond length
5500 of list */
5501 /* check that each element of each entry does not
5502 go beyond end of list */
5503 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5504 struct fealist *ea_response_data;
5505 rc = -ENODATA;
5506 /* validate_trans2_offsets() */
5507 /* BB check if start of smb + data_offset > &bcc+ bcc*/
5508 ea_response_data = (struct fealist *)
5509 (((char *) &pSMBr->hdr.Protocol) +
5510 data_offset);
5511 name_len = le32_to_cpu(ea_response_data->list_len);
5512 cFYI(1, ("ea length %d", name_len));
5513 if (name_len <= 8) {
5514 /* returned EA size zeroed at top of function */
5515 cFYI(1, ("empty EA list returned from server"));
5516 } else {
5517 /* account for ea list len */
5518 name_len -= 4;
5519 temp_fea = ea_response_data->list;
5520 temp_ptr = (char *)temp_fea;
5521 /* loop through checking if we have a matching
5522 name and then return the associated value */
5523 while (name_len > 0) {
5524 __u16 value_len;
5525 name_len -= 4;
5526 temp_ptr += 4;
5527 value_len =
5528 le16_to_cpu(temp_fea->value_len);
5529 /* BB validate that value_len falls within SMB,
5530 even though maximum for name_len is 255 */
5531 if (memcmp(temp_fea->name, ea_name,
5532 temp_fea->name_len) == 0) {
5533 /* found a match */
5534 rc = value_len;
5535 /* account for prefix user. and trailing null */
5536 if (rc <= (int)buf_size) {
5537 memcpy(ea_value,
5538 temp_fea->name+temp_fea->name_len+1,
5539 rc);
5540 /* ea values, unlike ea
5541 names, are not null
5542 terminated */
5543 } else if (buf_size == 0) {
5544 /* skip copy - calc size only */
5545 } else {
5546 /* stop before overrun buffer */
5547 rc = -ERANGE;
5548 }
5549 break;
5550 }
5551 name_len -= temp_fea->name_len;
5552 temp_ptr += temp_fea->name_len;
5553 /* account for trailing null */
5554 name_len--;
5555 temp_ptr++;
5556 name_len -= value_len;
5557 temp_ptr += value_len;
5558 /* No trailing null to account for in
5559 value_len. Go on to next EA */
5560 temp_fea = (struct fea *)temp_ptr;
5561 } 5558 }
5559 memcpy(EAData, temp_ptr, value_len);
5560 goto QAllEAsOut;
5561 }
5562 } else {
5563 /* account for prefix user. and trailing null */
5564 rc += (5 + 1 + name_len);
5565 if (rc < (int) buf_size) {
5566 memcpy(EAData, "user.", 5);
5567 EAData += 5;
5568 memcpy(EAData, temp_ptr, name_len);
5569 EAData += name_len;
5570 /* null terminate name */
5571 *EAData = 0;
5572 ++EAData;
5573 } else if (buf_size == 0) {
5574 /* skip copy - calc size only */
5575 } else {
5576 /* stop before overrun buffer */
5577 rc = -ERANGE;
5578 break;
5562 } 5579 }
5563 } 5580 }
5581 temp_ptr += name_len + 1 + value_len;
5582 temp_fea = (struct fea *)temp_ptr;
5564 } 5583 }
5584
5585 /* didn't find the named attribute */
5586 if (ea_name)
5587 rc = -ENODATA;
5588
5589QAllEAsOut:
5565 cifs_buf_release(pSMB); 5590 cifs_buf_release(pSMB);
5566 if (rc == -EAGAIN) 5591 if (rc == -EAGAIN)
5567 goto QEARetry; 5592 goto QAllEAsRetry;
5568 5593
5569 return (ssize_t)rc; 5594 return (ssize_t)rc;
5570} 5595}