aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAurelien Aptel <aaptel@suse.com>2017-02-22 08:47:17 -0500
committerSteve French <smfrench@gmail.com>2017-03-02 18:04:58 -0500
commitf0712928be1a66c99c35f871b4df7fa23ec1574a (patch)
tree3262f33e0131838da803cc1e7c20da2605bbc6f3
parentb9043cc5b99e9c93596a28647fd9f526f5bfa22c (diff)
CIFS: use DFS pathnames in SMB2+ Create requests
When connected to a DFS capable share, the client must set the SMB2_FLAGS_DFS_OPERATIONS flag in the SMB2 header and use DFS path names: "<server>\<share>\<path>" *without* leading \\. Sources: [MS-SMB2] 3.2.5.5 Receiving an SMB2 TREE_CONNECT Response > TreeConnect.IsDfsShare MUST be set to TRUE, if the SMB2_SHARE_CAP_DFS > bit is set in the Capabilities field of the response. [MS-SMB2] 3.2.4.3 Application Requests Opening a File > If TreeConnect.IsDfsShare is TRUE, the SMB2_FLAGS_DFS_OPERATIONS flag > is set in the Flags field. [MS-SMB2] 2.2.13 SMB2 CREATE Request, NameOffset: > If SMB2_FLAGS_DFS_OPERATIONS is set in the Flags field of the SMB2 > header, the file name includes a prefix that will be processed during > DFS name normalization as specified in section 3.3.5.9. Otherwise, the > file name is relative to the share that is identified by the TreeId in > the SMB2 header. Signed-off-by: Aurelien Aptel <aaptel@suse.com> Acked-by: Pavel Shilovsky <pshilov@microsoft.com> Signed-off-by: Steve French <smfrench@gmail.com>
-rw-r--r--fs/cifs/smb2pdu.c96
1 files changed, 80 insertions, 16 deletions
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 2fd93eeed15a..2069431b32e3 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1528,6 +1528,51 @@ add_durable_context(struct kvec *iov, unsigned int *num_iovec,
1528 return 0; 1528 return 0;
1529} 1529}
1530 1530
1531static int
1532alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len,
1533 const char *treename, const __le16 *path)
1534{
1535 int treename_len, path_len;
1536 struct nls_table *cp;
1537 const __le16 sep[] = {cpu_to_le16('\\'), cpu_to_le16(0x0000)};
1538
1539 /*
1540 * skip leading "\\"
1541 */
1542 treename_len = strlen(treename);
1543 if (treename_len < 2 || !(treename[0] == '\\' && treename[1] == '\\'))
1544 return -EINVAL;
1545
1546 treename += 2;
1547 treename_len -= 2;
1548
1549 path_len = UniStrnlen((wchar_t *)path, PATH_MAX);
1550
1551 /*
1552 * make room for one path separator between the treename and
1553 * path
1554 */
1555 *out_len = treename_len + 1 + path_len;
1556
1557 /*
1558 * final path needs to be null-terminated UTF16 with a
1559 * size aligned to 8
1560 */
1561
1562 *out_size = roundup((*out_len+1)*2, 8);
1563 *out_path = kzalloc(*out_size, GFP_KERNEL);
1564 if (!*out_path)
1565 return -ENOMEM;
1566
1567 cp = load_nls_default();
1568 cifs_strtoUTF16(*out_path, treename, treename_len, cp);
1569 UniStrcat(*out_path, sep);
1570 UniStrcat(*out_path, path);
1571 unload_nls(cp);
1572
1573 return 0;
1574}
1575
1531int 1576int
1532SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, 1577SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
1533 __u8 *oplock, struct smb2_file_all_info *buf, 1578 __u8 *oplock, struct smb2_file_all_info *buf,
@@ -1576,30 +1621,49 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
1576 req->ShareAccess = FILE_SHARE_ALL_LE; 1621 req->ShareAccess = FILE_SHARE_ALL_LE;
1577 req->CreateDisposition = cpu_to_le32(oparms->disposition); 1622 req->CreateDisposition = cpu_to_le32(oparms->disposition);
1578 req->CreateOptions = cpu_to_le32(oparms->create_options & CREATE_OPTIONS_MASK); 1623 req->CreateOptions = cpu_to_le32(oparms->create_options & CREATE_OPTIONS_MASK);
1579 uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2;
1580 /* do not count rfc1001 len field */
1581 req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req) - 4);
1582 1624
1583 iov[0].iov_base = (char *)req; 1625 iov[0].iov_base = (char *)req;
1584 /* 4 for rfc1002 length field */ 1626 /* 4 for rfc1002 length field */
1585 iov[0].iov_len = get_rfc1002_length(req) + 4; 1627 iov[0].iov_len = get_rfc1002_length(req) + 4;
1586
1587 /* MUST set path len (NameLength) to 0 opening root of share */
1588 req->NameLength = cpu_to_le16(uni_path_len - 2);
1589 /* -1 since last byte is buf[0] which is sent below (path) */ 1628 /* -1 since last byte is buf[0] which is sent below (path) */
1590 iov[0].iov_len--; 1629 iov[0].iov_len--;
1591 if (uni_path_len % 8 != 0) { 1630
1592 copy_size = uni_path_len / 8 * 8; 1631 req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req) - 4);
1593 if (copy_size < uni_path_len) 1632
1594 copy_size += 8; 1633 /* [MS-SMB2] 2.2.13 NameOffset:
1595 1634 * If SMB2_FLAGS_DFS_OPERATIONS is set in the Flags field of
1596 copy_path = kzalloc(copy_size, GFP_KERNEL); 1635 * the SMB2 header, the file name includes a prefix that will
1597 if (!copy_path) 1636 * be processed during DFS name normalization as specified in
1598 return -ENOMEM; 1637 * section 3.3.5.9. Otherwise, the file name is relative to
1599 memcpy((char *)copy_path, (const char *)path, 1638 * the share that is identified by the TreeId in the SMB2
1600 uni_path_len); 1639 * header.
1640 */
1641 if (tcon->share_flags & SHI1005_FLAGS_DFS) {
1642 int name_len;
1643
1644 req->hdr.sync_hdr.Flags |= SMB2_FLAGS_DFS_OPERATIONS;
1645 rc = alloc_path_with_tree_prefix(&copy_path, &copy_size,
1646 &name_len,
1647 tcon->treeName, path);
1648 if (rc)
1649 return rc;
1650 req->NameLength = cpu_to_le16(name_len * 2);
1601 uni_path_len = copy_size; 1651 uni_path_len = copy_size;
1602 path = copy_path; 1652 path = copy_path;
1653 } else {
1654 uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2;
1655 /* MUST set path len (NameLength) to 0 opening root of share */
1656 req->NameLength = cpu_to_le16(uni_path_len - 2);
1657 if (uni_path_len % 8 != 0) {
1658 copy_size = roundup(uni_path_len, 8);
1659 copy_path = kzalloc(copy_size, GFP_KERNEL);
1660 if (!copy_path)
1661 return -ENOMEM;
1662 memcpy((char *)copy_path, (const char *)path,
1663 uni_path_len);
1664 uni_path_len = copy_size;
1665 path = copy_path;
1666 }
1603 } 1667 }
1604 1668
1605 iov[1].iov_len = uni_path_len; 1669 iov[1].iov_len = uni_path_len;