aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifsproto.h7
-rw-r--r--fs/cifs/cifssmb.c214
-rw-r--r--fs/cifs/inode.c2
-rw-r--r--fs/cifs/xattr.c8
4 files changed, 54 insertions, 177 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 5646727e33f5..88e2bc44ac58 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -363,13 +363,10 @@ extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
363 __u32 filter, struct file *file, int multishot, 363 __u32 filter, struct file *file, int multishot,
364 const struct nls_table *nls_codepage); 364 const struct nls_table *nls_codepage);
365extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, 365extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
366 const unsigned char *searchName, char *EAData, 366 const unsigned char *searchName,
367 const unsigned char *ea_name, char *EAData,
367 size_t bufsize, const struct nls_table *nls_codepage, 368 size_t bufsize, const struct nls_table *nls_codepage,
368 int remap_special_chars); 369 int remap_special_chars);
369extern ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
370 const unsigned char *searchName, const unsigned char *ea_name,
371 unsigned char *ea_value, size_t buf_size,
372 const struct nls_table *nls_codepage, int remap_special_chars);
373extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, 370extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon,
374 const char *fileName, const char *ea_name, 371 const char *fileName, const char *ea_name,
375 const void *ea_value, const __u16 ea_value_len, 372 const void *ea_value, const __u16 ea_value_len,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index e197e1647d5d..d6d40b883abc 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -5269,12 +5269,22 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5269 cifs_buf_release(pSMB); 5269 cifs_buf_release(pSMB);
5270 return rc; 5270 return rc;
5271} 5271}
5272
5272#ifdef CONFIG_CIFS_XATTR 5273#ifdef CONFIG_CIFS_XATTR
5274/*
5275 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5276 * function used by listxattr and getxattr type calls. When ea_name is set,
5277 * it looks for that attribute name and stuffs that value into the EAData
5278 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5279 * buffer. In both cases, the return value is either the length of the
5280 * resulting data or a negative error code. If EAData is a NULL pointer then
5281 * the data isn't copied to it, but the length is returned.
5282 */
5273ssize_t 5283ssize_t
5274CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, 5284CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5275 const unsigned char *searchName, 5285 const unsigned char *searchName, const unsigned char *ea_name,
5276 char *EAData, size_t buf_size, 5286 char *EAData, size_t buf_size,
5277 const struct nls_table *nls_codepage, int remap) 5287 const struct nls_table *nls_codepage, int remap)
5278{ 5288{
5279 /* BB assumes one setup word */ 5289 /* BB assumes one setup word */
5280 TRANSACTION2_QPI_REQ *pSMB = NULL; 5290 TRANSACTION2_QPI_REQ *pSMB = NULL;
@@ -5403,27 +5413,46 @@ QAllEAsRetry:
5403 goto QAllEAsOut; 5413 goto QAllEAsOut;
5404 } 5414 }
5405 5415
5406 /* account for prefix user. and trailing null */ 5416 if (ea_name) {
5407 rc += (5 + 1 + name_len); 5417 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5408 if (rc < (int) buf_size) { 5418 temp_ptr += name_len + 1;
5409 memcpy(EAData, "user.", 5); 5419 rc = value_len;
5410 EAData += 5; 5420 if (buf_size == 0)
5411 memcpy(EAData, temp_ptr, name_len); 5421 goto QAllEAsOut;
5412 EAData += name_len; 5422 if ((size_t)value_len > buf_size) {
5413 /* null terminate name */ 5423 rc = -ERANGE;
5414 *EAData = 0; 5424 goto QAllEAsOut;
5415 ++EAData; 5425 }
5416 } else if (buf_size == 0) { 5426 memcpy(EAData, temp_ptr, value_len);
5417 /* skip copy - calc size only */ 5427 goto QAllEAsOut;
5428 }
5418 } else { 5429 } else {
5419 /* stop before overrun buffer */ 5430 /* account for prefix user. and trailing null */
5420 rc = -ERANGE; 5431 rc += (5 + 1 + name_len);
5421 break; 5432 if (rc < (int) buf_size) {
5433 memcpy(EAData, "user.", 5);
5434 EAData += 5;
5435 memcpy(EAData, temp_ptr, name_len);
5436 EAData += name_len;
5437 /* null terminate name */
5438 *EAData = 0;
5439 ++EAData;
5440 } else if (buf_size == 0) {
5441 /* skip copy - calc size only */
5442 } else {
5443 /* stop before overrun buffer */
5444 rc = -ERANGE;
5445 break;
5446 }
5422 } 5447 }
5423 temp_ptr += name_len + 1 + value_len; 5448 temp_ptr += name_len + 1 + value_len;
5424 temp_fea = (struct fea *)temp_ptr; 5449 temp_fea = (struct fea *)temp_ptr;
5425 } 5450 }
5426 5451
5452 /* didn't find the named attribute */
5453 if (ea_name)
5454 rc = -ENODATA;
5455
5427QAllEAsOut: 5456QAllEAsOut:
5428 cifs_buf_release(pSMB); 5457 cifs_buf_release(pSMB);
5429 if (rc == -EAGAIN) 5458 if (rc == -EAGAIN)
@@ -5432,155 +5461,6 @@ QAllEAsOut:
5432 return (ssize_t)rc; 5461 return (ssize_t)rc;
5433} 5462}
5434 5463
5435ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5436 const unsigned char *searchName, const unsigned char *ea_name,
5437 unsigned char *ea_value, size_t buf_size,
5438 const struct nls_table *nls_codepage, int remap)
5439{
5440 TRANSACTION2_QPI_REQ *pSMB = NULL;
5441 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5442 int rc = 0;
5443 int bytes_returned;
5444 int name_len;
5445 struct fea *temp_fea;
5446 char *temp_ptr;
5447 __u16 params, byte_count;
5448
5449 cFYI(1, ("In Query EA path %s", searchName));
5450QEARetry:
5451 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5452 (void **) &pSMBr);
5453 if (rc)
5454 return rc;
5455
5456 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5457 name_len =
5458 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5459 PATH_MAX, nls_codepage, remap);
5460 name_len++; /* trailing null */
5461 name_len *= 2;
5462 } else { /* BB improve the check for buffer overruns BB */
5463 name_len = strnlen(searchName, PATH_MAX);
5464 name_len++; /* trailing null */
5465 strncpy(pSMB->FileName, searchName, name_len);
5466 }
5467
5468 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5469 pSMB->TotalDataCount = 0;
5470 pSMB->MaxParameterCount = cpu_to_le16(2);
5471 /* BB find exact max SMB PDU from sess structure BB */
5472 pSMB->MaxDataCount = cpu_to_le16(4000);
5473 pSMB->MaxSetupCount = 0;
5474 pSMB->Reserved = 0;
5475 pSMB->Flags = 0;
5476 pSMB->Timeout = 0;
5477 pSMB->Reserved2 = 0;
5478 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5479 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5480 pSMB->DataCount = 0;
5481 pSMB->DataOffset = 0;
5482 pSMB->SetupCount = 1;
5483 pSMB->Reserved3 = 0;
5484 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5485 byte_count = params + 1 /* pad */ ;
5486 pSMB->TotalParameterCount = cpu_to_le16(params);
5487 pSMB->ParameterCount = pSMB->TotalParameterCount;
5488 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5489 pSMB->Reserved4 = 0;
5490 pSMB->hdr.smb_buf_length += byte_count;
5491 pSMB->ByteCount = cpu_to_le16(byte_count);
5492
5493 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5494 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5495 if (rc) {
5496 cFYI(1, ("Send error in Query EA = %d", rc));
5497 } else { /* decode response */
5498 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5499
5500 /* BB also check enough total bytes returned */
5501 /* BB we need to improve the validity checking
5502 of these trans2 responses */
5503 if (rc || (pSMBr->ByteCount < 4))
5504 rc = -EIO; /* bad smb */
5505 /* else if (pFindData){
5506 memcpy((char *) pFindData,
5507 (char *) &pSMBr->hdr.Protocol +
5508 data_offset, kl);
5509 }*/ else {
5510 /* check that length of list is not more than bcc */
5511 /* check that each entry does not go beyond length
5512 of list */
5513 /* check that each element of each entry does not
5514 go beyond end of list */
5515 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5516 struct fealist *ea_response_data;
5517 rc = -ENODATA;
5518 /* validate_trans2_offsets() */
5519 /* BB check if start of smb + data_offset > &bcc+ bcc*/
5520 ea_response_data = (struct fealist *)
5521 (((char *) &pSMBr->hdr.Protocol) +
5522 data_offset);
5523 name_len = le32_to_cpu(ea_response_data->list_len);
5524 cFYI(1, ("ea length %d", name_len));
5525 if (name_len <= 8) {
5526 /* returned EA size zeroed at top of function */
5527 cFYI(1, ("empty EA list returned from server"));
5528 } else {
5529 /* account for ea list len */
5530 name_len -= 4;
5531 temp_fea = ea_response_data->list;
5532 temp_ptr = (char *)temp_fea;
5533 /* loop through checking if we have a matching
5534 name and then return the associated value */
5535 while (name_len > 0) {
5536 __u16 value_len;
5537 name_len -= 4;
5538 temp_ptr += 4;
5539 value_len =
5540 le16_to_cpu(temp_fea->value_len);
5541 /* BB validate that value_len falls within SMB,
5542 even though maximum for name_len is 255 */
5543 if (memcmp(temp_fea->name, ea_name,
5544 temp_fea->name_len) == 0) {
5545 /* found a match */
5546 rc = value_len;
5547 /* account for prefix user. and trailing null */
5548 if (rc <= (int)buf_size) {
5549 memcpy(ea_value,
5550 temp_fea->name+temp_fea->name_len+1,
5551 rc);
5552 /* ea values, unlike ea
5553 names, are not null
5554 terminated */
5555 } else if (buf_size == 0) {
5556 /* skip copy - calc size only */
5557 } else {
5558 /* stop before overrun buffer */
5559 rc = -ERANGE;
5560 }
5561 break;
5562 }
5563 name_len -= temp_fea->name_len;
5564 temp_ptr += temp_fea->name_len;
5565 /* account for trailing null */
5566 name_len--;
5567 temp_ptr++;
5568 name_len -= value_len;
5569 temp_ptr += value_len;
5570 /* No trailing null to account for in
5571 value_len. Go on to next EA */
5572 temp_fea = (struct fea *)temp_ptr;
5573 }
5574 }
5575 }
5576 }
5577 cifs_buf_release(pSMB);
5578 if (rc == -EAGAIN)
5579 goto QEARetry;
5580
5581 return (ssize_t)rc;
5582}
5583
5584int 5464int
5585CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName, 5465CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5586 const char *ea_name, const void *ea_value, 5466 const char *ea_name, const void *ea_value,
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index e3fda978f481..5e9cc9c2fc7d 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -366,7 +366,7 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
366 char ea_value[4]; 366 char ea_value[4];
367 __u32 mode; 367 __u32 mode;
368 368
369 rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS", 369 rc = CIFSSMBQAllEAs(xid, cifs_sb->tcon, path, "SETFILEBITS",
370 ea_value, 4 /* size of buf */, cifs_sb->local_nls, 370 ea_value, 4 /* size of buf */, cifs_sb->local_nls,
371 cifs_sb->mnt_cifs_flags & 371 cifs_sb->mnt_cifs_flags &
372 CIFS_MOUNT_MAP_SPECIAL_CHR); 372 CIFS_MOUNT_MAP_SPECIAL_CHR);
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index a75afa3dd9e1..3e2ef0de1209 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -244,7 +244,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
244 /* revalidate/getattr then populate from inode */ 244 /* revalidate/getattr then populate from inode */
245 } /* BB add else when above is implemented */ 245 } /* BB add else when above is implemented */
246 ea_name += 5; /* skip past user. prefix */ 246 ea_name += 5; /* skip past user. prefix */
247 rc = CIFSSMBQueryEA(xid, pTcon, full_path, ea_name, ea_value, 247 rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value,
248 buf_size, cifs_sb->local_nls, 248 buf_size, cifs_sb->local_nls,
249 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 249 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
250 } else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) { 250 } else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) {
@@ -252,7 +252,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
252 goto get_ea_exit; 252 goto get_ea_exit;
253 253
254 ea_name += 4; /* skip past os2. prefix */ 254 ea_name += 4; /* skip past os2. prefix */
255 rc = CIFSSMBQueryEA(xid, pTcon, full_path, ea_name, ea_value, 255 rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value,
256 buf_size, cifs_sb->local_nls, 256 buf_size, cifs_sb->local_nls,
257 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 257 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
258 } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS, 258 } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
@@ -364,8 +364,8 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
364 /* if proc/fs/cifs/streamstoxattr is set then 364 /* if proc/fs/cifs/streamstoxattr is set then
365 search server for EAs or streams to 365 search server for EAs or streams to
366 returns as xattrs */ 366 returns as xattrs */
367 rc = CIFSSMBQAllEAs(xid, pTcon, full_path, data, buf_size, 367 rc = CIFSSMBQAllEAs(xid, pTcon, full_path, NULL, data,
368 cifs_sb->local_nls, 368 buf_size, cifs_sb->local_nls,
369 cifs_sb->mnt_cifs_flags & 369 cifs_sb->mnt_cifs_flags &
370 CIFS_MOUNT_MAP_SPECIAL_CHR); 370 CIFS_MOUNT_MAP_SPECIAL_CHR);
371 371