Add support for DFS in SMB2+
Subsystems (2)
v3 cover Add support for DFS in SMB2+
This series of patch tries to implement the get_dfs_refer operation for SMB2+.
In SMB2+, DFS resolving is now done through an FSCTL (patch #7). The relevant Microsoft specifications for this are:
MS-SMB2: 3.2.4.20 Application Requests an IO Control Code Operation
MS-SMB2: 3.2.4.20.3 Application Requests DFS Referral Information
MS-SMB2: 3.2.5.14 Receiving an SMB2 IOCTL Response
MS-SMB2: 3.2.5.14.4 Handling a DFS Referral Information Response
MS-DFSC: 2.2 Message Syntax (but really the whole document is useful)
The DFS response payload however is identical. Patch #1 moves the DFS response parsing out of SMB1 code and makes it work on any version of SMB.
DFS code has 2 "main" entry points: initial mounting and automount (when a DFS link is accessed/traversed).
When automounting, cifs.ko calls build_path_from_dentry() which only makes treename-prefixed paths when the tcon has the SMB_IN_DFS_SHARE. This flag is checked in tcon->Flags which is never touched by SMB2 code as it sets tcon->share_flags on connexion.
* CIFS requires to prefix all pathnames with the treename prefix when connected to a DFS server, so the current build_path_from_dentry() makes sense for CIFS.
* For SMB2+ it seems only the Create request requires the treename prefix. Simply making the function check for both CIFS SMB2+ flag for DFS to add a prefix does not work as the server has different expectations about which packet can have/require a DFS pathname.
Patch #2 adds build_path_from_dentry_optional_prefix() with an extra bool arg to decide to prefix or not. The automount code path always ask for it. Patch #6 modifies SMB2_open() to add the treename prefix to the given path if the server requires it.
We try to use an IPC connection first for the DFS request. Patch #3 adds a flag to SMB2_ioctl() to force the usage of ipc_tid. The SMB2 get_dfs_refer operation tries with the flag set and fallback to a share connection if that doesn't work.
Patch #4 updates the type of ipc_tid from u16 to u32 as that is what a Tid is in SMB2+. This is correct and really needed since in SMB2 Samba doesn't use sequential tree id but random ones in the 32bit space.
As part of the mouting process a IPC tcon is made (I suspect we don't need it anymore in SMB3). This tcon doesn't respect the signing requirement. This is fixed by patch #5.
Finally the SMB2+ implementation of the get_dfs_referral operation is added in all supported SMB versions in patch #7.
I've sucessfuly tested this (v1.0 and v3.0) against a Windows Server 2016 DFS setup and a Samba DFS setup.
Samba used to only accepts DFS referrals requests on an IPC connexion, which is in violation of the spec. A patch was sent on samba-technical and merged. It is not required anymore.
https://lists.samba.org/archive/samba-technical/2017-February/118859.html
Changes since v2:
* add use_ipc flag to SMB2_open()
* make smb2_get_dfs_refer() try IPC connections first
* use first_entry_or_null() instead of first_entry() on the tcon list
* protect tcon list access with spinlock
* add inc/dec of the tcon reference number, protected by spinlock
Aurelien Aptel (7):
CIFS: move DFS response parsing out of SMB1 code
CIFS: add build_path_from_dentry_optional_prefix()
CIFS: add use_ipc flag to SMB2_ioctl()
CIFS: let ses->ipc_tid hold smb2 TreeIds
CIFS: set signing flag in SMB2+ TreeConnect if needed
CIFS: use DFS pathnames in SMB2+ Create requests
CIFS: implement get_dfs_refer for SMB2+
fs/cifs/cifs_dfs_ref.c | 4 +- fs/cifs/cifsglob.h | 2 +- fs/cifs/cifspdu.h | 16 ++++--- fs/cifs/cifsproto.h | 7 +++ fs/cifs/cifssmb.c | 119 ++--------------------------------------------- fs/cifs/dir.c | 13 +++++- fs/cifs/misc.c | 105 +++++++++++++++++++++++++++++++++++++++++ fs/cifs/smb2file.c | 3 +- fs/cifs/smb2ops.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++--- fs/cifs/smb2pdu.c | 114 +++++++++++++++++++++++++++++++++++++-------- fs/cifs/smb2pdu.h | 8 ++++ fs/cifs/smb2proto.h | 3 +- 12 files changed, 365 insertions(+), 152 deletions(-)
Signature · 1 line
2.10.2
A message that is not in the archive (sent off-list or not yet received): 20170228184034.18771-1-aaptel-IBi9RG/[email protected]
PATCH v3 1/7 CIFS: move DFS response parsing out of SMB1 code
since the DFS payload is not tied to the SMB version we can:
* isolate the DFS payload in its own struct, and include that struct in packet structs
* move the function that parses the response to misc.c and make it work on the new DFS payload struct (add payload size and utf16 flag as a result).
--- fs/cifs/cifspdu.h | 16 ++++--- fs/cifs/cifsproto.h | 5 +++ fs/cifs/cifssmb.c | 119 +++------------------------------------------------- fs/cifs/misc.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 125 insertions(+), 120 deletions(-)
fs/cifs/cifspdu.h +10 -6
@@ -2086,17 +2086,21 @@ typedef struct dfs_referral_level_3 { /* version 4 is same, + one flag bit */__u8 ServiceSiteGuid[16 ];/* MBZ, ignored */ } __attribute__((packed)) REFERRAL3; -typedef struct smb_com_transaction_get_dfs_refer_rsp { -struct smb_hdr hdr;/* wct = 10 */ -struct trans2_resp t2; -__u16 ByteCount; -__u8 Pad; +struct get_dfs_referral_rsp {__le16 PathConsumed;__le16 NumberOfReferrals;__le32 DFSFlags;REFERRAL3 referrals[1 ];/* array of level 3 dfs_referral structures */ /* followed by the strings pointed to by the referral structures */ -} __attribute__((packed))TRANSACTION2_GET_DFS_REFER_RSP ; +} __packed; + +typedef struct smb_com_transaction_get_dfs_refer_rsp { +struct smb_hdr hdr;/* wct = 10 */ +struct trans2_resp t2; +__u16 ByteCount; +__u8 Pad; +struct get_dfs_referral_rsp dfs_data; +} __packed TRANSACTION2_GET_DFS_REFER_RSP;/* DFS Flags */ #define DFSREF_REFERRAL_SERVER 0x00000001/* all targets are DFS roots */
fs/cifs/cifsproto.h +5 -0
@@ -284,6 +284,11 @@ extern int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,const struct nls_table *nls_codepage, unsigned int *num_referrals, struct dfs_info3_param **referrals, int remap); +extern int parse_dfs_referrals (struct get_dfs_referral_rsp *rsp,u32 rsp_size, +unsigned int *num_of_nodes, +struct dfs_info3_param **target_nodes, +const struct nls_table *nls_codepage,int remap, +const char *searchName,bool is_unicode);extern void reset_cifs_unix_caps (unsigned int xid,struct cifs_tcon *tcon,struct cifs_sb_info *cifs_sb,struct smb_vol *vol);
fs/cifs/cifssmb.c +5 -114
131 lines not on this page · raw message
fs/cifs/misc.c +105 -0
108 lines not on this page · raw message
Signature · 1 line
2.10.2
A message that is not in the archive (sent off-list or not yet received): 20170228184034.18771-2-aaptel-IBi9RG/[email protected]
Pavel Shilovsky
Acked-byRe: [PATCH v3 1/7] CIFS: move DFS response parsing out of SMB1 code
2017-02-28 10:40 GMT-08:00 Aurelien Aptel <aaptel-IBi9RG/[email protected]>:
Quoted 316 lines
since the DFS payload is not tied to the SMB version we can:
* isolate the DFS payload in its own struct, and include that struct in packet structs
* move the function that parses the response tomisc.cand make it work on the new DFS payload struct (add payload size and utf16 flag as a result).Signed-off-by Aurelien Aptel <aaptel-IBi9RG/[email protected]>--- fs/cifs/cifspdu.h | 16 ++++--- fs/cifs/cifsproto.h | 5 +++ fs/cifs/cifssmb.c | 119 +++------------------------------------------------- fs/cifs/misc.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 125 insertions(+), 120 deletions(-)fs/cifs/cifspdu.h +10
-6@@ -2086,17 +2086,21 @@ typedef struct dfs_referral_level_3 { /* version 4 is same, + one flag bit */__u8 ServiceSiteGuid[16 ];/* MBZ, ignored */ } __attribute__((packed)) REFERRAL3; -typedef struct smb_com_transaction_get_dfs_refer_rsp { -struct smb_hdr hdr;/* wct = 10 */ -struct trans2_resp t2; -__u16 ByteCount; -__u8 Pad; +struct get_dfs_referral_rsp {__le16 PathConsumed;__le16 NumberOfReferrals;__le32 DFSFlags;REFERRAL3 referrals[1 ];/* array of level 3 dfs_referral structures */ /* followed by the strings pointed to by the referral structures */ -} __attribute__((packed))TRANSACTION2_GET_DFS_REFER_RSP ; +} __packed; + +typedef struct smb_com_transaction_get_dfs_refer_rsp { +struct smb_hdr hdr;/* wct = 10 */ +struct trans2_resp t2; +__u16 ByteCount; +__u8 Pad; +struct get_dfs_referral_rsp dfs_data; +} __packed TRANSACTION2_GET_DFS_REFER_RSP;/* DFS Flags */ #define DFSREF_REFERRAL_SERVER 0x00000001/* all targets are DFS roots */ fs/cifs/cifsproto.h +5
-0@@ -284,6 +284,11 @@ extern int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,const struct nls_table *nls_codepage, unsigned int *num_referrals, struct dfs_info3_param **referrals, int remap); +extern int parse_dfs_referrals (struct get_dfs_referral_rsp *rsp,u32 rsp_size, +unsigned int *num_of_nodes, +struct dfs_info3_param **target_nodes, +const struct nls_table *nls_codepage,int remap, +const char *searchName,bool is_unicode);extern void reset_cifs_unix_caps (unsigned int xid,struct cifs_tcon *tcon,struct cifs_sb_info *cifs_sb,struct smb_vol *vol);fs/cifs/cifssmb.c +5
-114@@ -4786,117 +4786,6 @@ CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,return rc; } -/* parses DFS refferal V3 structure -* caller is responsible for freeing target_nodes -* returns: -* on success - 0 -* on failure - errno -*/ -static int -parse_DFS_referrals (TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, -unsigned int *num_of_nodes, -struct dfs_info3_param **target_nodes, -const struct nls_table *nls_codepage,int remap, -const char *searchName) -{ -int i, rc =0 ; -char *data_end; -bool is_unicode; -struct dfs_referral_level_3 *ref; - -if (pSMBr->hdr.Flags2 &SMBFLG2_UNICODE ) - is_unicode = true; -else - is_unicode = false; - *num_of_nodes =le16_to_cpu (pSMBr->NumberOfReferrals); - -if (*num_of_nodes <1 ) { -cifs_dbg (VFS ,"num_referrals: must be at least > 0, but we get num_referrals = %d\n" , - *num_of_nodes); - rc = -EINVAL ; - goto parse_DFS_referrals_exit; - } - - ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals); -if (ref->VersionNumber !=cpu_to_le16 (3 )) { -cifs_dbg (VFS ,"Referrals of V%d version are not supported, should be V3\n" , -le16_to_cpu (ref->VersionNumber)); - rc = -EINVAL ; - goto parse_DFS_referrals_exit; - } - -/* get the upper boundary of the resp buffer */ - data_end = (char *)(&(pSMBr->PathConsumed)) + -le16_to_cpu (pSMBr->t2.DataCount); - -cifs_dbg (FYI ,"num_referrals: %d dfs flags: 0x%x ...\n" , - *num_of_nodes,le32_to_cpu (pSMBr->DFSFlags)); - - *target_nodes =kcalloc (*num_of_nodes,sizeof (struct dfs_info3_param ), -GFP_KERNEL ); -if (*target_nodes ==NULL ) { - rc = -ENOMEM ; - goto parse_DFS_referrals_exit; - } - -/* collect necessary data from referrals */ -for (i =0 ; i < *num_of_nodes; i++) { -char *temp; -int max_len; -struct dfs_info3_param *node = (*target_nodes)+i; - - node->flags =le32_to_cpu (pSMBr->DFSFlags); -if (is_unicode) { -__le16 *tmp =kmalloc (strlen (searchName)*2 +2 , -GFP_KERNEL ); -if (tmp ==NULL ) { - rc = -ENOMEM ; - goto parse_DFS_referrals_exit; - } -cifsConvertToUTF16 ((__le16 *) tmp, searchName, -PATH_MAX , nls_codepage, remap); - node->path_consumed =cifs_utf16_bytes (tmp, -le16_to_cpu (pSMBr->PathConsumed), - nls_codepage); -kfree (tmp); - }else - node->path_consumed =le16_to_cpu (pSMBr->PathConsumed); - - node->server_type =le16_to_cpu (ref->ServerType); - node->ref_flag =le16_to_cpu (ref->ReferralEntryFlags); - -/* copy DfsPath */ - temp = (char *)ref +le16_to_cpu (ref->DfsPathOffset); - max_len = data_end - temp; - node->path_name =cifs_strndup_from_utf16 (temp, max_len, - is_unicode, nls_codepage); -if (!node->path_name) { - rc = -ENOMEM ; - goto parse_DFS_referrals_exit; - } - -/* copy link target UNC */ - temp = (char *)ref +le16_to_cpu (ref->NetworkAddressOffset); - max_len = data_end - temp; - node->node_name =cifs_strndup_from_utf16 (temp, max_len, - is_unicode, nls_codepage); -if (!node->node_name) { - rc = -ENOMEM ; - goto parse_DFS_referrals_exit; - } - - ref++; - } - -parse_DFS_referrals_exit: -if (rc) { -free_dfs_info_array (*target_nodes, *num_of_nodes); - *target_nodes =NULL ; - *num_of_nodes =0 ; - } -return rc; -} - int CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses, const char *search_name, struct dfs_info3_param **target_nodes,@@ -4993,9 +4882,11 @@ CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses, get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));/* parse returned result into more usable form */ - rc =parse_DFS_referrals (pSMBr, num_of_nodes, - target_nodes, nls_codepage, remap, - search_name); + rc =parse_dfs_referrals (&pSMBr->dfs_data, +le16_to_cpu (pSMBr->t2.DataCount), + num_of_nodes, target_nodes, nls_codepage, + remap, search_name, + pSMBr->hdr.Flags2 &SMBFLG2_UNICODE ); GetDFSRefExit:cifs_buf_release (pSMB);fs/cifs/misc.c +105
-1@@ -640,3 +640,108 @@ cifs_add_pending_open(struct cifs_fid *fid, struct tcon_link *tlink,cifs_add_pending_open_locked (fid, tlink, open);spin_unlock (&tlink_tcon (open->tlink)->open_file_lock); } + +/* parses DFS refferal V3 structure +* caller is responsible for freeing target_nodes +* returns: +* - on success - 0 +* - on failure - errno +*/ +int +parse_dfs_referrals (struct get_dfs_referral_rsp *rsp,u32 rsp_size, +unsigned int *num_of_nodes, +struct dfs_info3_param **target_nodes, +const struct nls_table *nls_codepage,int remap, +const char *searchName,bool is_unicode) +{ +int i, rc =0 ; +char *data_end; +struct dfs_referral_level_3 *ref; + + *num_of_nodes =le16_to_cpu (rsp->NumberOfReferrals); + +if (*num_of_nodes <1 ) { +cifs_dbg (VFS ,"num_referrals: must be at least > 0, but we get num_referrals = %d\n" , + *num_of_nodes); + rc = -EINVAL ; + goto parse_DFS_referrals_exit; + } + + ref = (struct dfs_referral_level_3 *) &(rsp->referrals); +if (ref->VersionNumber !=cpu_to_le16 (3 )) { +cifs_dbg (VFS ,"Referrals of V%d version are not supported, should be V3\n" , +le16_to_cpu (ref->VersionNumber)); + rc = -EINVAL ; + goto parse_DFS_referrals_exit; + } + +/* get the upper boundary of the resp buffer */ + data_end = (char *)rsp + rsp_size; + +cifs_dbg (FYI ,"num_referrals: %d dfs flags: 0x%x ...\n" , + *num_of_nodes,le32_to_cpu (rsp->DFSFlags)); + + *target_nodes =kcalloc (*num_of_nodes,sizeof (struct dfs_info3_param ), +GFP_KERNEL ); +if (*target_nodes ==NULL ) { + rc = -ENOMEM ; + goto parse_DFS_referrals_exit; + } + +/* collect necessary data from referrals */ +for (i =0 ; i < *num_of_nodes; i++) { +char *temp; +int max_len; +struct dfs_info3_param *node = (*target_nodes)+i; + + node->flags =le32_to_cpu (rsp->DFSFlags); +if (is_unicode) { +__le16 *tmp =kmalloc (strlen (searchName)*2 +2 , +GFP_KERNEL ); +if (tmp ==NULL ) { + rc = -ENOMEM ; + goto parse_DFS_referrals_exit; + } +cifsConvertToUTF16 ((__le16 *) tmp, searchName, +PATH_MAX , nls_codepage, remap); + node->path_consumed =cifs_utf16_bytes (tmp, +le16_to_cpu (rsp->PathConsumed), + nls_codepage); +kfree (tmp); + }else + node->path_consumed =le16_to_cpu (rsp->PathConsumed); + + node->server_type =le16_to_cpu (ref->ServerType); + node->ref_flag =le16_to_cpu (ref->ReferralEntryFlags); + +/* copy DfsPath */ + temp = (char *)ref +le16_to_cpu (ref->DfsPathOffset); + max_len = data_end - temp; + node->path_name =cifs_strndup_from_utf16 (temp, max_len, + is_unicode, nls_codepage); +if (!node->path_name) { + rc = -ENOMEM ; + goto parse_DFS_referrals_exit; + } + +/* copy link target UNC */ + temp = (char *)ref +le16_to_cpu (ref->NetworkAddressOffset); + max_len = data_end - temp; + node->node_name =cifs_strndup_from_utf16 (temp, max_len, + is_unicode, nls_codepage); +if (!node->node_name) { + rc = -ENOMEM ; + goto parse_DFS_referrals_exit; + } + + ref++; + } + +parse_DFS_referrals_exit: +if (rc) { +free_dfs_info_array (*target_nodes, *num_of_nodes); + *target_nodes =NULL ; + *num_of_nodes =0 ; + } +return rc; +} --2.10.2
Quoted 4 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 2 lines
Best regards, Pavel Shilovsky
PATCH v3 2/7 CIFS: add build_path_from_dentry_optional_prefix()
In reply to a message not in the archivethis function does the same thing as add build_path_from_dentry() but takes a boolean parameter to decide whether or not to prefix the path with the tree name.
we cannot rely on tcon->Flags & SMB_SHARE_IS_IN_DFS for SMB2 as smb2 code never sets tcon->Flags but it sets tcon->share_flags and it seems the SMB_SHARE_IS_IN_DFS has different semantics in SMB2: the prefix shouldn't be added everytime it was in SMB1.
--- fs/cifs/cifs_dfs_ref.c | 4 +++- fs/cifs/cifsproto.h | 2 ++ fs/cifs/dir.c | 13 ++++++++++++- 3 files changed, 17 insertions(+), 2 deletions(-)
fs/cifs/cifs_dfs_ref.c +3 -1
@@ -302,7 +302,9 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)* gives us the latter, so we must adjust the result. */ mnt =ERR_PTR (-ENOMEM ); - full_path =build_path_from_dentry (mntpt); + +/* always use tree name prefix */ + full_path =build_path_from_dentry_optional_prefix (mntpt, true);if (full_path ==NULL ) goto cdda_exit;
fs/cifs/cifsproto.h +2 -0
@@ -61,6 +61,8 @@ extern void exit_cifs_idmap(void);extern int init_cifs_spnego (void );extern void exit_cifs_spnego (void );extern char *build_path_from_dentry (struct dentry *); +extern char *build_path_from_dentry_optional_prefix (struct dentry *direntry, +bool prefix); extern char *cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
fs/cifs/dir.c +12 -1
@@ -81,6 +81,17 @@ cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,char *build_path_from_dentry (struct dentry *direntry) { +struct cifs_sb_info *cifs_sb =CIFS_SB (direntry->d_sb); +struct cifs_tcon *tcon =cifs_sb_master_tcon (cifs_sb); +bool prefix = tcon->Flags &SMB_SHARE_IS_IN_DFS ; + +return build_path_from_dentry_optional_prefix (direntry, + prefix); +} + +char * +build_path_from_dentry_optional_prefix (struct dentry *direntry,bool prefix) +{struct dentry *temp;int namelen;int dfsplen;
@@ -92,7 +103,7 @@ build_path_from_dentry(struct dentry *direntry)unsigned seq; dirsep =CIFS_DIR_SEP (cifs_sb); -if (tcon->Flags &SMB_SHARE_IS_IN_DFS ) +if (prefix) dfsplen =strnlen (tcon->treeName,MAX_TREE_SIZE +1 );else dfsplen =0 ;
Signature · 1 line
2.10.2
A message that is not in the archive (sent off-list or not yet received): 20170228184034.18771-3-aaptel-IBi9RG/[email protected]
Pavel Shilovsky
Acked-byRe: [PATCH v3 2/7] CIFS: add build_path_from_dentry_optional_prefix()
2017-02-28 10:40 GMT-08:00 Aurelien Aptel <aaptel-IBi9RG/[email protected]>:
Quoted 78 lines
this function does the same thing as add
build_path_from_dentry()but takes a boolean parameter to decide whether or not to prefix the path with the tree name.we cannot rely on
tcon->Flags&SMB_SHARE_IS_IN_DFSfor SMB2 as smb2 code never setstcon->Flagsbut it setstcon->share_flagsand it seems theSMB_SHARE_IS_IN_DFShas different semantics in SMB2: the prefix shouldn't be added everytime it was in SMB1.Signed-off-by Aurelien Aptel <aaptel-IBi9RG/[email protected]>--- fs/cifs/cifs_dfs_ref.c | 4 +++- fs/cifs/cifsproto.h | 2 ++ fs/cifs/dir.c | 13 ++++++++++++- 3 files changed, 17 insertions(+), 2 deletions(-)fs/cifs/cifs_dfs_ref.c +3
-1@@ -302,7 +302,9 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)* gives us the latter, so we must adjust the result. */ mnt =ERR_PTR (-ENOMEM ); - full_path =build_path_from_dentry (mntpt); + +/* always use tree name prefix */ + full_path =build_path_from_dentry_optional_prefix (mntpt, true);if (full_path ==NULL ) goto cdda_exit;fs/cifs/cifsproto.h +2
-0@@ -61,6 +61,8 @@ extern void exit_cifs_idmap(void);extern int init_cifs_spnego (void );extern void exit_cifs_spnego (void );extern char *build_path_from_dentry (struct dentry *); +extern char *build_path_from_dentry_optional_prefix (struct dentry *direntry, +bool prefix); extern char *cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,fs/cifs/dir.c +12
-2@@ -81,6 +81,17 @@ cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,char *build_path_from_dentry (struct dentry *direntry) { +struct cifs_sb_info *cifs_sb =CIFS_SB (direntry->d_sb); +struct cifs_tcon *tcon =cifs_sb_master_tcon (cifs_sb); +bool prefix = tcon->Flags &SMB_SHARE_IS_IN_DFS ; + +return build_path_from_dentry_optional_prefix (direntry, + prefix); +} + +char * +build_path_from_dentry_optional_prefix (struct dentry *direntry,bool prefix) +{struct dentry *temp;int namelen;int dfsplen;@@ -92,7 +103,7 @@ build_path_from_dentry(struct dentry *direntry)unsigned seq; dirsep =CIFS_DIR_SEP (cifs_sb); -if (tcon->Flags &SMB_SHARE_IS_IN_DFS ) +if (prefix) dfsplen =strnlen (tcon->treeName,MAX_TREE_SIZE +1 );else dfsplen =0 ; --2.10.2
Quoted 4 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 2 lines
Best regards, Pavel Shilovsky
PATCH v3 3/7 CIFS: add use_ipc flag to SMB2_ioctl()
In reply to a message not in the archivewhen set, use the session IPC tree id instead of the tid in the provided tcon.
--- fs/cifs/smb2file.c | 3 ++- fs/cifs/smb2ops.c | 23 ++++++++++++++++------- fs/cifs/smb2pdu.c | 17 +++++++++++++++-- fs/cifs/smb2proto.h | 3 ++- 4 files changed, 35 insertions(+), 11 deletions(-)
fs/cifs/smb2file.c +2 -1
@@ -73,7 +73,8 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, nr_ioctl_req.Timeout =0 ;/* use server default (120 seconds) */ nr_ioctl_req.Reserved =0 ; rc =SMB2_ioctl (xid, oparms->tcon, fid->persistent_fid, - fid->volatile_fid,FSCTL_LMR_REQUEST_RESILIENCY , true, + fid->volatile_fid,FSCTL_LMR_REQUEST_RESILIENCY , + true/* is_fsctl */ , false/* use_ipc */ , (char *)&nr_ioctl_req,sizeof (nr_ioctl_req),NULL ,NULL /* no return info */ );if (rc == -EOPNOTSUPP ) {
fs/cifs/smb2ops.c +16 -7
@@ -282,6 +282,7 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon) rc =SMB2_ioctl (xid, tcon,NO_FILE_ID ,NO_FILE_ID ,FSCTL_QUERY_NETWORK_INTERFACE_INFO , true/* is_fsctl */ , + false/* use_ipc */ ,NULL /* no data input */ ,0 /* no data input */ , (char **)&out_buf, &ret_data_len);if (rc !=0 )
@@ -571,6 +572,7 @@ SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon, rc =SMB2_ioctl (xid, tcon, persistent_fid, volatile_fid,FSCTL_SRV_REQUEST_RESUME_KEY , true/* is_fsctl */ , + false/* use_ipc */ ,NULL ,0 /* no input */ , (char **)&res_key, &ret_data_len);
@@ -635,7 +637,8 @@ smb2_clone_range(const unsigned int xid,/* Request server copy to target from src identified by key */ rc =SMB2_ioctl (xid, tcon, trgtfile->fid.persistent_fid, trgtfile->fid.volatile_fid,FSCTL_SRV_COPYCHUNK_WRITE , - true/* is_fsctl */ , (char *)pcchunk, + true/* is_fsctl */ , false/* use_ipc */ , + (char *)pcchunk,sizeof (struct copychunk_ioctl ), (char **)&retbuf, &ret_data_len);if (rc ==0 ) {
@@ -787,7 +790,8 @@ static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon, rc =SMB2_ioctl (xid, tcon, cfile->fid.persistent_fid, cfile->fid.volatile_fid,FSCTL_SET_SPARSE , - true/* is_fctl */ , &setsparse,1 ,NULL ,NULL ); + true/* is_fctl */ , false/* use_ipc */ , + &setsparse,1 ,NULL ,NULL );if (rc) { tcon->broken_sparse_sup = true;cifs_dbg (FYI ,"set sparse rc = %d\n" , rc);
@@ -857,7 +861,8 @@ smb2_duplicate_extents(const unsigned int xid, rc =SMB2_ioctl (xid, tcon, trgtfile->fid.persistent_fid, trgtfile->fid.volatile_fid,FSCTL_DUPLICATE_EXTENTS_TO_FILE , - true/* is_fsctl */ , (char *)&dup_ext_buf, + true/* is_fsctl */ , false/* use_ipc */ , + (char *)&dup_ext_buf,sizeof (struct duplicate_extents_to_file ),NULL , &ret_data_len);
@@ -891,7 +896,8 @@ smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon,return SMB2_ioctl (xid, tcon, cfile->fid.persistent_fid, cfile->fid.volatile_fid,FSCTL_SET_INTEGRITY_INFORMATION , - true/* is_fsctl */ , (char *)&integr_info, + true/* is_fsctl */ , false/* use_ipc */ , + (char *)&integr_info,sizeof (struct fsctl_set_integrity_information_req ),NULL , &ret_data_len);
@@ -910,7 +916,8 @@ smb3_enum_snapshots(const unsigned int xid, struct cifs_tcon *tcon, rc =SMB2_ioctl (xid, tcon, cfile->fid.persistent_fid, cfile->fid.volatile_fid,FSCTL_SRV_ENUMERATE_SNAPSHOTS , - true/* is_fsctl */ ,NULL ,0 /* no input data */ , + true/* is_fsctl */ , false/* use_ipc */ , +NULL ,0 /* no input data */ , (char **)&retbuf, &ret_data_len); cifs_dbg(FYI, "enum snaphots ioctl returned %d and ret buflen is %d\n",
@@ -1220,7 +1227,8 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon, rc =SMB2_ioctl (xid, tcon, cfile->fid.persistent_fid, cfile->fid.volatile_fid,FSCTL_SET_ZERO_DATA , - true/* is_fctl */ , (char *)&fsctl_buf, + true/* is_fctl */ , false/* use_ipc */ , + (char *)&fsctl_buf,sizeof (struct file_zero_data_information ),NULL ,NULL );free_xid (xid);return rc;
@@ -1254,7 +1262,8 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon, rc =SMB2_ioctl (xid, tcon, cfile->fid.persistent_fid, cfile->fid.volatile_fid,FSCTL_SET_ZERO_DATA , - true/* is_fctl */ , (char *)&fsctl_buf, + true/* is_fctl */ , false/* use_ipc */ , + (char *)&fsctl_buf,sizeof (struct file_zero_data_information ),NULL ,NULL );free_xid (xid);return rc;
fs/cifs/smb2pdu.c +15 -2
@@ -620,6 +620,7 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) rc =SMB2_ioctl (xid, tcon,NO_FILE_ID ,NO_FILE_ID ,FSCTL_VALIDATE_NEGOTIATE_INFO , true/* is_fsctl */ , + false/* use_ipc */ , (char *)&vneg_inbuf,sizeof (struct validate_negotiate_info_req ), (char **)&pneg_rsp, &rsplen);
@@ -1683,8 +1684,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,*/ int SMB2_ioctl (const unsigned int xid,struct cifs_tcon *tcon,u64 persistent_fid, -u64 volatile_fid,u32 opcode,bool is_fsctl,char *in_data, -u32 indatalen,char **out_data,u32 *plen/* returned data len */ ) +u64 volatile_fid,u32 opcode,bool is_fsctl,bool use_ipc, +char *in_data,u32 indatalen, +char **out_data,u32 *plen/* returned data len */ ) {struct smb2_ioctl_req *req;struct smb2_ioctl_rsp *rsp;
@@ -1721,6 +1723,16 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,if (rc)return rc; +if (use_ipc) { +if (ses->ipc_tid ==0 ) { +cifs_small_buf_release (req); +return -ENOTCONN ; + } + +cifs_dbg (FYI ,"replacing tid 0x%x with IPC tid 0x%x\n" , + req->hdr.sync_hdr.TreeId, ses->ipc_tid); + req->hdr.sync_hdr.TreeId = ses->ipc_tid; + }if (encryption_required (tcon)) flags |=CIFS_TRANSFORM_REQ ;
@@ -1843,6 +1855,7 @@ SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon, rc =SMB2_ioctl (xid, tcon, persistent_fid, volatile_fid,FSCTL_SET_COMPRESSION , true/* is_fsctl */ , + false/* use_ipc */ , (char *)&fsctl_input/* data input */ ,2 /* in data len */ , &ret_data/* out data */ ,NULL );
fs/cifs/smb2proto.h +2 -1
@@ -121,7 +121,8 @@ extern int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, struct smb2_err_rsp **err_buf);extern int SMB2_ioctl (const unsigned int xid,struct cifs_tcon *tcon,u64 persistent_fid,u64 volatile_fid,u32 opcode, -bool is_fsctl,char *in_data,u32 indatalen, +bool is_fsctl,bool use_ipc, +char *in_data,u32 indatalen,char **out_data,u32 *plen/* returned data len */ );extern int SMB2_close (const unsigned int xid,struct cifs_tcon *tcon,u64 persistent_file_id,u64 volatile_file_id);
Signature · 1 line
2.10.2
A message that is not in the archive (sent off-list or not yet received): 20170228184034.18771-4-aaptel-IBi9RG/[email protected]
Pavel Shilovsky
Reviewed-byRe: [PATCH v3 3/7] CIFS: add use_ipc flag to SMB2_ioctl()
2017-02-28 10:40 GMT-08:00 Aurelien Aptel <aaptel-IBi9RG/[email protected]>:
Quoted 181 lines
when set, use the session IPC tree id instead of the tid in the provided tcon.
Signed-off-by Aurelien Aptel <aaptel-IBi9RG/[email protected]>--- fs/cifs/smb2file.c | 3 ++- fs/cifs/smb2ops.c | 23 ++++++++++++++++------- fs/cifs/smb2pdu.c | 17 +++++++++++++++-- fs/cifs/smb2proto.h | 3 ++- 4 files changed, 35 insertions(+), 11 deletions(-)fs/cifs/smb2file.c +2
-1@@ -73,7 +73,8 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, nr_ioctl_req.Timeout =0 ;/* use server default (120 seconds) */ nr_ioctl_req.Reserved =0 ; rc =SMB2_ioctl (xid, oparms->tcon, fid->persistent_fid, - fid->volatile_fid,FSCTL_LMR_REQUEST_RESILIENCY , true, + fid->volatile_fid,FSCTL_LMR_REQUEST_RESILIENCY , + true/* is_fsctl */ , false/* use_ipc */ , (char *)&nr_ioctl_req,sizeof (nr_ioctl_req),NULL ,NULL /* no return info */ );if (rc == -EOPNOTSUPP ) {fs/cifs/smb2ops.c +16
-7@@ -282,6 +282,7 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon) rc =SMB2_ioctl (xid, tcon,NO_FILE_ID ,NO_FILE_ID ,FSCTL_QUERY_NETWORK_INTERFACE_INFO , true/* is_fsctl */ , + false/* use_ipc */ ,NULL /* no data input */ ,0 /* no data input */ , (char **)&out_buf, &ret_data_len);if (rc !=0 )@@ -571,6 +572,7 @@ SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon, rc =SMB2_ioctl (xid, tcon, persistent_fid, volatile_fid,FSCTL_SRV_REQUEST_RESUME_KEY , true/* is_fsctl */ , + false/* use_ipc */ ,NULL ,0 /* no input */ , (char **)&res_key, &ret_data_len);@@ -635,7 +637,8 @@ smb2_clone_range(const unsigned int xid,/* Request server copy to target from src identified by key */ rc =SMB2_ioctl (xid, tcon, trgtfile->fid.persistent_fid, trgtfile->fid.volatile_fid,FSCTL_SRV_COPYCHUNK_WRITE , - true/* is_fsctl */ , (char *)pcchunk, + true/* is_fsctl */ , false/* use_ipc */ , + (char *)pcchunk,sizeof (struct copychunk_ioctl ), (char **)&retbuf, &ret_data_len);if (rc ==0 ) {@@ -787,7 +790,8 @@ static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon, rc =SMB2_ioctl (xid, tcon, cfile->fid.persistent_fid, cfile->fid.volatile_fid,FSCTL_SET_SPARSE , - true/* is_fctl */ , &setsparse,1 ,NULL ,NULL ); + true/* is_fctl */ , false/* use_ipc */ , + &setsparse,1 ,NULL ,NULL );if (rc) { tcon->broken_sparse_sup = true;cifs_dbg (FYI ,"set sparse rc = %d\n" , rc);@@ -857,7 +861,8 @@ smb2_duplicate_extents(const unsigned int xid, rc =SMB2_ioctl (xid, tcon, trgtfile->fid.persistent_fid, trgtfile->fid.volatile_fid,FSCTL_DUPLICATE_EXTENTS_TO_FILE , - true/* is_fsctl */ , (char *)&dup_ext_buf, + true/* is_fsctl */ , false/* use_ipc */ , + (char *)&dup_ext_buf,sizeof (struct duplicate_extents_to_file ),NULL , &ret_data_len);@@ -891,7 +896,8 @@ smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon,return SMB2_ioctl (xid, tcon, cfile->fid.persistent_fid, cfile->fid.volatile_fid,FSCTL_SET_INTEGRITY_INFORMATION , - true/* is_fsctl */ , (char *)&integr_info, + true/* is_fsctl */ , false/* use_ipc */ , + (char *)&integr_info,sizeof (struct fsctl_set_integrity_information_req ),NULL , &ret_data_len);@@ -910,7 +916,8 @@ smb3_enum_snapshots(const unsigned int xid, struct cifs_tcon *tcon, rc =SMB2_ioctl (xid, tcon, cfile->fid.persistent_fid, cfile->fid.volatile_fid,FSCTL_SRV_ENUMERATE_SNAPSHOTS , - true/* is_fsctl */ ,NULL ,0 /* no input data */ , + true/* is_fsctl */ , false/* use_ipc */ , +NULL ,0 /* no input data */ , (char **)&retbuf, &ret_data_len); cifs_dbg(FYI, "enum snaphots ioctl returned %d and ret buflen is %d\n",@@ -1220,7 +1227,8 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon, rc =SMB2_ioctl (xid, tcon, cfile->fid.persistent_fid, cfile->fid.volatile_fid,FSCTL_SET_ZERO_DATA , - true/* is_fctl */ , (char *)&fsctl_buf, + true/* is_fctl */ , false/* use_ipc */ , + (char *)&fsctl_buf,sizeof (struct file_zero_data_information ),NULL ,NULL );free_xid (xid);return rc;@@ -1254,7 +1262,8 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon, rc =SMB2_ioctl (xid, tcon, cfile->fid.persistent_fid, cfile->fid.volatile_fid,FSCTL_SET_ZERO_DATA , - true/* is_fctl */ , (char *)&fsctl_buf, + true/* is_fctl */ , false/* use_ipc */ , + (char *)&fsctl_buf,sizeof (struct file_zero_data_information ),NULL ,NULL );free_xid (xid);return rc;fs/cifs/smb2pdu.c +15
-2@@ -620,6 +620,7 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) rc =SMB2_ioctl (xid, tcon,NO_FILE_ID ,NO_FILE_ID ,FSCTL_VALIDATE_NEGOTIATE_INFO , true/* is_fsctl */ , + false/* use_ipc */ , (char *)&vneg_inbuf,sizeof (struct validate_negotiate_info_req ), (char **)&pneg_rsp, &rsplen);@@ -1683,8 +1684,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,*/ int SMB2_ioctl (const unsigned int xid,struct cifs_tcon *tcon,u64 persistent_fid, -u64 volatile_fid,u32 opcode,bool is_fsctl,char *in_data, -u32 indatalen,char **out_data,u32 *plen/* returned data len */ ) +u64 volatile_fid,u32 opcode,bool is_fsctl,bool use_ipc, +char *in_data,u32 indatalen, +char **out_data,u32 *plen/* returned data len */ ) {struct smb2_ioctl_req *req;struct smb2_ioctl_rsp *rsp;@@ -1721,6 +1723,16 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,if (rc)return rc; +if (use_ipc) { +if (ses->ipc_tid ==0 ) { +cifs_small_buf_release (req); +return -ENOTCONN ; + } + +cifs_dbg (FYI ,"replacing tid 0x%x with IPC tid 0x%x\n" , + req->hdr.sync_hdr.TreeId, ses->ipc_tid); + req->hdr.sync_hdr.TreeId = ses->ipc_tid; + }if (encryption_required (tcon)) flags |=CIFS_TRANSFORM_REQ ;@@ -1843,6 +1855,7 @@ SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon, rc =SMB2_ioctl (xid, tcon, persistent_fid, volatile_fid,FSCTL_SET_COMPRESSION , true/* is_fsctl */ , + false/* use_ipc */ , (char *)&fsctl_input/* data input */ ,2 /* in data len */ , &ret_data/* out data */ ,NULL );fs/cifs/smb2proto.h +2
-2@@ -121,7 +121,8 @@ extern int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, struct smb2_err_rsp **err_buf);extern int SMB2_ioctl (const unsigned int xid,struct cifs_tcon *tcon,u64 persistent_fid,u64 volatile_fid,u32 opcode, -bool is_fsctl,char *in_data,u32 indatalen, +bool is_fsctl,bool use_ipc, +char *in_data,u32 indatalen,char **out_data,u32 *plen/* returned data len */ );extern int SMB2_close (const unsigned int xid,struct cifs_tcon *tcon,u64 persistent_file_id,u64 volatile_file_id); --2.10.2
Quoted 4 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 2 lines
Best regards, Pavel Shilovsky
PATCH v3 4/7 CIFS: let ses->ipc_tid hold smb2 TreeIds
In reply to a message not in the archivethe TreeId field went from 2 bytes in CIFS to 4 bytes in SMB2+. this commit updates the size of the ipc_tid field of a cifs_ses, which was still using 2 bytes.
--- fs/cifs/cifsglob.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/cifs/cifsglob.h +1 -1
@@ -822,7 +822,7 @@ struct cifs_ses {int ses_count;/* reference counter */ enum statusEnum status;unsigned overrideSecFlg;/* if non-zero override global sec flags */ -__u16 ipc_tid;/* special tid for connection to IPC share */ +__u32 ipc_tid;/* special tid for connection to IPC share */ char *serverOS;/* name of operating system underlying server */ char *serverNOS;/* name of network operating system of server */ char *serverDomain;/* security realm of server */
Signature · 1 line
2.10.2
A message that is not in the archive (sent off-list or not yet received): 20170228184034.18771-5-aaptel-IBi9RG/[email protected]
Pavel Shilovsky
Reviewed-byRe: [PATCH v3 4/7] CIFS: let ses->ipc_tid hold smb2 TreeIds
2017-02-28 10:40 GMT-08:00 Aurelien Aptel <aaptel-IBi9RG/[email protected]>:
Quoted 25 lines
the TreeId field went from 2 bytes in CIFS to 4 bytes in SMB2+. this commit updates the size of the
ipc_tidfield of acifs_ses, which was still using 2 bytes.Signed-off-by Aurelien Aptel <aaptel-IBi9RG/[email protected]>--- fs/cifs/cifsglob.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)fs/cifs/cifsglob.h +1
-2@@ -822,7 +822,7 @@ struct cifs_ses {int ses_count;/* reference counter */ enum statusEnum status;unsigned overrideSecFlg;/* if non-zero override global sec flags */ -__u16 ipc_tid;/* special tid for connection to IPC share */ +__u32 ipc_tid;/* special tid for connection to IPC share */ char *serverOS;/* name of operating system underlying server */ char *serverNOS;/* name of network operating system of server */ char *serverDomain;/* security realm of server */ --2.10.2
Quoted 4 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 2 lines
Best regards, Pavel Shilovsky
PATCH v3 5/7 CIFS: set signing flag in SMB2+ TreeConnect if needed
In reply to a message not in the archivecifs_enable_signing() already sets server->sign according to what the server requires/offers and what mount options allows/forbids, so use that.
this is required for IPC tcon that connects to signing-required servers.
--- fs/cifs/smb2pdu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/cifs/smb2pdu.c +2 -2
@@ -1168,8 +1168,8 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,/* since no tcon, smb2_init can not do this, so do here */ req->hdr.sync_hdr.SessionId = ses->Suid; -/* if (ses->server->sec_mode & SECMODE_SIGN_REQUIRED) -req->hdr.Flags |= SMB2_FLAGS_SIGNED; */ +if (ses->server->sign) + req->hdr.sync_hdr.Flags |=SMB2_FLAGS_SIGNED ; }else if (encryption_required (tcon)) flags |=CIFS_TRANSFORM_REQ ;
Signature · 1 line
2.10.2
A message that is not in the archive (sent off-list or not yet received): 20170228184034.18771-6-aaptel-IBi9RG/[email protected]
Pavel Shilovsky
Reviewed-byRe: [PATCH v3 5/7] CIFS: set signing flag in SMB2+ TreeConnect if needed
2017-02-28 10:40 GMT-08:00 Aurelien Aptel <aaptel-IBi9RG/[email protected]>:
Quoted 29 lines
cifs_enable_signing()already setsserver->signaccording to what the server requires/offers and what mount options allows/forbids, so use that.this is required for IPC tcon that connects to signing-required servers.
Signed-off-by Aurelien Aptel <aaptel-IBi9RG/[email protected]>--- fs/cifs/smb2pdu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)fs/cifs/smb2pdu.c +2
-3@@ -1168,8 +1168,8 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,/* since no tcon, smb2_init can not do this, so do here */ req->hdr.sync_hdr.SessionId = ses->Suid; -/* if (ses->server->sec_mode & SECMODE_SIGN_REQUIRED) -req->hdr.Flags |= SMB2_FLAGS_SIGNED; */ +if (ses->server->sign) + req->hdr.sync_hdr.Flags |=SMB2_FLAGS_SIGNED ; }else if (encryption_required (tcon)) flags |=CIFS_TRANSFORM_REQ ; --2.10.2
Quoted 4 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 2 lines
Best regards, Pavel Shilovsky
PATCH v3 6/7 CIFS: use DFS pathnames in SMB2+ Create requests
In reply to a message not in the archiveWhen 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
Quoted 2 lines
TreeConnect.IsDfsShare MUST be set to TRUE, if the
SMB2_SHARE_CAP_DFSbit is set in the Capabilities field of the response.
[MS-SMB2] 3.2.4.3 Application Requests Opening a File
Quoted 2 lines
If TreeConnect.IsDfsShare is TRUE, the
SMB2_FLAGS_DFS_OPERATIONSflag is set in the Flags field.
[MS-SMB2] 2.2.13 SMB2 CREATE Request, NameOffset:
Quoted 5 lines
If
SMB2_FLAGS_DFS_OPERATIONSis 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.
--- fs/cifs/smb2pdu.c | 93 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 77 insertions(+), 16 deletions(-)
fs/cifs/smb2pdu.c +77 -16
@@ -1528,6 +1528,48 @@ add_durable_context(struct kvec *iov, unsigned int *num_iovec,return 0 ; } +static int +alloc_path_with_tree_prefix (__le16 **out_path,int *out_size,int *out_len, +const char *treename,const __le16 *path) +{ +int treename_len, path_len; +const __le16 sep[] = {cpu_to_le16 ('\\' ),cpu_to_le16 (0x0000 )}; + +/* +* skip leading "\\" +*/ + treename_len =strlen (treename); +if (treename_len <2 || !(treename[0 ] =='\\' && treename[1 ] =='\\' )) +return -EINVAL ; + + treename +=2 ; + treename_len -=2 ; + + path_len =UniStrnlen ((wchar_t *)path,PATH_MAX ); + +/* +* make room for one path separator between the treename and +* path +*/ + *out_len = treename_len +1 + path_len; + +/* +* final path needs to be null-terminated UTF16 with a +* size aligned to 8 +*/ + + *out_size =roundup ((*out_len+1 )*2 ,8 ); + *out_path =kzalloc (*out_size,GFP_KERNEL ); +if (!*out_path) +return -ENOMEM ; + +cifs_strtoUTF16 (*out_path, treename, treename_len,load_nls_default ()); +UniStrcat (*out_path, sep); +UniStrcat (*out_path, path); + +return 0 ; +} + int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, __u8 *oplock, struct smb2_file_all_info *buf,
@@ -1576,30 +1618,49 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, req->ShareAccess =FILE_SHARE_ALL_LE ; req->CreateDisposition =cpu_to_le32 (oparms->disposition); req->CreateOptions =cpu_to_le32 (oparms->create_options &CREATE_OPTIONS_MASK ); - uni_path_len = (2 *UniStrnlen ((wchar_t *)path,PATH_MAX )) +2 ; -/* do not count rfc1001 len field */ - req->NameOffset =cpu_to_le16 (sizeof (struct smb2_create_req ) -4 ); iov[0 ].iov_base = (char *)req;/* 4 for rfc1002 length field */ iov[0 ].iov_len =get_rfc1002_length (req) +4 ; - -/* MUST set path len (NameLength) to 0 opening root of share */ - req->NameLength =cpu_to_le16 (uni_path_len -2 );/* -1 since last byte is buf[0] which is sent below (path) */ iov[0 ].iov_len--; -if (uni_path_len %8 !=0 ) { - copy_size = uni_path_len /8 *8 ; -if (copy_size < uni_path_len) - copy_size +=8 ; - - copy_path =kzalloc (copy_size,GFP_KERNEL ); -if (!copy_path) -return -ENOMEM ; -memcpy ((char *)copy_path, (const char *)path, - uni_path_len); + + req->NameOffset =cpu_to_le16 (sizeof (struct smb2_create_req ) -4 ); + +/* [MS-SMB2] 2.2.13 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. +*/ +if (tcon->share_flags &SHI1005_FLAGS_DFS ) { +int name_len; + + req->hdr.sync_hdr.Flags |=SMB2_FLAGS_DFS_OPERATIONS ; + rc =alloc_path_with_tree_prefix (©_path, ©_size, + &name_len, + tcon->treeName, path); +if (rc) +return rc; + req->NameLength =cpu_to_le16 (name_len *2 ); uni_path_len = copy_size; path = copy_path; + }else { + uni_path_len = (2 *UniStrnlen ((wchar_t *)path,PATH_MAX )) +2 ; +/* MUST set path len (NameLength) to 0 opening root of share */ + req->NameLength =cpu_to_le16 (uni_path_len -2 ); +if (uni_path_len %8 !=0 ) { + copy_size =roundup (uni_path_len,8 ); + copy_path =kzalloc (copy_size,GFP_KERNEL ); +if (!copy_path) +return -ENOMEM ; +memcpy ((char *)copy_path, (const char *)path, + uni_path_len); + uni_path_len = copy_size; + path = copy_path; + } } iov[1 ].iov_len = uni_path_len;
Signature · 1 line
2.10.2
A message that is not in the archive (sent off-list or not yet received): 20170228184034.18771-7-aaptel-IBi9RG/[email protected]
Pavel Shilovsky
Acked-byRe: [PATCH v3 6/7] CIFS: use DFS pathnames in SMB2+ Create requests
2017-02-28 10:40 GMT-08:00 Aurelien Aptel <aaptel-IBi9RG/[email protected]>:
Quoted 148 lines
When connected to a DFS capable share, the client must set the
SMB2_FLAGS_DFS_OPERATIONSflag 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_CONNECTResponseQuoted 2 lines
TreeConnect.IsDfsShare MUST be set to TRUE, if the
SMB2_SHARE_CAP_DFSbit is set in the Capabilities field of the response.[MS-SMB2] 3.2.4.3 Application Requests Opening a File
Quoted 2 lines
If TreeConnect.IsDfsShare is TRUE, the
SMB2_FLAGS_DFS_OPERATIONSflag is set in the Flags field.[MS-SMB2] 2.2.13 SMB2 CREATE Request, NameOffset:
Quoted 5 lines
If
SMB2_FLAGS_DFS_OPERATIONSis 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-IBi9RG/[email protected]>--- fs/cifs/smb2pdu.c | 93 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 77 insertions(+), 16 deletions(-)fs/cifs/smb2pdu.c +77
-17@@ -1528,6 +1528,48 @@ add_durable_context(struct kvec *iov, unsigned int *num_iovec,return 0 ; } +static int +alloc_path_with_tree_prefix (__le16 **out_path,int *out_size,int *out_len, +const char *treename,const __le16 *path) +{ +int treename_len, path_len; +const __le16 sep[] = {cpu_to_le16 ('\\' ),cpu_to_le16 (0x0000 )}; + +/* +* skip leading "\\" +*/ + treename_len =strlen (treename); +if (treename_len <2 || !(treename[0 ] =='\\' && treename[1 ] =='\\' )) +return -EINVAL ; + + treename +=2 ; + treename_len -=2 ; + + path_len =UniStrnlen ((wchar_t *)path,PATH_MAX ); + +/* +* make room for one path separator between the treename and +* path +*/ + *out_len = treename_len +1 + path_len; + +/* +* final path needs to be null-terminated UTF16 with a +* size aligned to 8 +*/ + + *out_size =roundup ((*out_len+1 )*2 ,8 ); + *out_path =kzalloc (*out_size,GFP_KERNEL ); +if (!*out_path) +return -ENOMEM ; + +cifs_strtoUTF16 (*out_path, treename, treename_len,load_nls_default ()); +UniStrcat (*out_path, sep); +UniStrcat (*out_path, path); + +return 0 ; +} + int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, __u8 *oplock, struct smb2_file_all_info *buf,@@ -1576,30 +1618,49 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, req->ShareAccess =FILE_SHARE_ALL_LE ; req->CreateDisposition =cpu_to_le32 (oparms->disposition); req->CreateOptions =cpu_to_le32 (oparms->create_options &CREATE_OPTIONS_MASK ); - uni_path_len = (2 *UniStrnlen ((wchar_t *)path,PATH_MAX )) +2 ; -/* do not count rfc1001 len field */ - req->NameOffset =cpu_to_le16 (sizeof (struct smb2_create_req ) -4 ); iov[0 ].iov_base = (char *)req;/* 4 for rfc1002 length field */ iov[0 ].iov_len =get_rfc1002_length (req) +4 ; - -/* MUST set path len (NameLength) to 0 opening root of share */ - req->NameLength =cpu_to_le16 (uni_path_len -2 );/* -1 since last byte is buf[0] which is sent below (path) */ iov[0 ].iov_len--; -if (uni_path_len %8 !=0 ) { - copy_size = uni_path_len /8 *8 ; -if (copy_size < uni_path_len) - copy_size +=8 ; - - copy_path =kzalloc (copy_size,GFP_KERNEL ); -if (!copy_path) -return -ENOMEM ; -memcpy ((char *)copy_path, (const char *)path, - uni_path_len); + + req->NameOffset =cpu_to_le16 (sizeof (struct smb2_create_req ) -4 ); + +/* [MS-SMB2] 2.2.13 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. +*/ +if (tcon->share_flags &SHI1005_FLAGS_DFS ) { +int name_len; + + req->hdr.sync_hdr.Flags |=SMB2_FLAGS_DFS_OPERATIONS ; + rc =alloc_path_with_tree_prefix (©_path, ©_size, + &name_len, + tcon->treeName, path); +if (rc) +return rc; + req->NameLength =cpu_to_le16 (name_len *2 ); uni_path_len = copy_size; path = copy_path; + }else { + uni_path_len = (2 *UniStrnlen ((wchar_t *)path,PATH_MAX )) +2 ; +/* MUST set path len (NameLength) to 0 opening root of share */ + req->NameLength =cpu_to_le16 (uni_path_len -2 ); +if (uni_path_len %8 !=0 ) { + copy_size =roundup (uni_path_len,8 ); + copy_path =kzalloc (copy_size,GFP_KERNEL ); +if (!copy_path) +return -ENOMEM ; +memcpy ((char *)copy_path, (const char *)path, + uni_path_len); + uni_path_len = copy_size; + path = copy_path; + } } iov[1 ].iov_len = uni_path_len; --2.10.2
Quoted 4 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 2 lines
Best regards, Pavel Shilovsky
PATCH v3 7/7 CIFS: implement get_dfs_refer for SMB2+
In reply to a message not in the archivein SMB2+ the get_dfs_refer operation uses a FSCTL. The request can be made on any Tree Connection according to the specs. Since Samba only accepted it on an IPC connection until recently, try that first.
https://lists.samba.org/archive/samba-technical/2017-February/118859.html
3.2.4.20.3 Application Requests DFS Referral Information:
Quoted 6 lines
The client MUST search for an existing Session and TreeConnect to any share on the server identified by ServerName for the user identified by UserCredentials. If no Session and TreeConnect are found, the client MUST establish a new Session and TreeConnect to IPC$ on the target server as described in section 3.2.4.2 using the supplied ServerName and UserCredentials.
--- fs/cifs/smb2ops.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/smb2pdu.h | 8 +++++ 2 files changed, 108 insertions(+)
fs/cifs/smb2ops.c +100 -0
@@ -1104,6 +1104,102 @@ smb2_new_lease_key(struct cifs_fid *fid)generate_random_uuid (fid->lease_key); } +static int +smb2_get_dfs_refer (const unsigned int xid,struct cifs_ses *ses, +const char *search_name, +struct dfs_info3_param **target_nodes, +unsigned int *num_of_nodes, +const struct nls_table *nls_codepage,int remap) +{ +int rc; +__le16 *utf16_path =NULL ; +int utf16_path_len =0 ; +struct cifs_tcon *tcon; +struct fsctl_get_dfs_referral_req *dfs_req =NULL ; +struct get_dfs_referral_rsp *dfs_rsp =NULL ; +u32 dfs_req_size =0 , dfs_rsp_size =0 ; + +cifs_dbg (FYI ,"smb2_get_dfs_refer path <%s>\n" , search_name); + +/* +* Use any tcon from the current session. Here, the first one. +*/ +spin_lock (&cifs_tcp_ses_lock); + tcon = list_first_entry_or_null(&ses->tcon_list, struct cifs_tcon, tcon_list); +if (tcon) + tcon->tc_count++; +spin_unlock (&cifs_tcp_ses_lock); + +if (!tcon) { +cifs_dbg (VFS ,"session %p has no tcon available for a dfs referral request\n" , + ses); + rc = -ENOTCONN ; + goto out; + } + + utf16_path =cifs_strndup_to_utf16 (search_name,PATH_MAX , + &utf16_path_len, + nls_codepage, remap); +if (!utf16_path) { + rc = -ENOMEM ; + goto out; + } + + dfs_req_size =sizeof (*dfs_req) + utf16_path_len; + dfs_req =kzalloc (dfs_req_size,GFP_KERNEL ); +if (!dfs_req) { + rc = -ENOMEM ; + goto out; + } + +/* Highest DFS referral version understood */ + dfs_req->MaxReferralLevel =cpu_to_le16 (DFS_VERSION ); + +/* Path to resolve in an UTF-16 null-terminated string */ +memcpy (dfs_req->RequestFileName, utf16_path, utf16_path_len); + +do { +/* try first with IPC */ + rc =SMB2_ioctl (xid, tcon,NO_FILE_ID ,NO_FILE_ID , +FSCTL_DFS_GET_REFERRALS , + true/* is_fsctl */ , true/* use_ipc */ , + (char *)dfs_req, dfs_req_size, + (char **)&dfs_rsp, &dfs_rsp_size); +if (rc == -ENOTCONN ) { +/* try with normal tcon */ + rc =SMB2_ioctl (xid, tcon,NO_FILE_ID ,NO_FILE_ID , +FSCTL_DFS_GET_REFERRALS , + true/* is_fsctl */ , false/*use_ipc*/ , + (char *)dfs_req, dfs_req_size, + (char **)&dfs_rsp, &dfs_rsp_size); + } + }while (rc == -EAGAIN ); + +if (rc) { +cifs_dbg (VFS ,"ioctl error in smb2_get_dfs_refer rc=%d\n" , rc); + goto out; + } + + rc =parse_dfs_referrals (dfs_rsp, dfs_rsp_size, + num_of_nodes, target_nodes, + nls_codepage, remap, search_name, + true/* is_unicode */ ); +if (rc) { +cifs_dbg (VFS ,"parse error in smb2_get_dfs_refer rc=%d\n" , rc); + goto out; + } + + out: +if (tcon) { +spin_lock (&cifs_tcp_ses_lock); + tcon->tc_count--; +spin_unlock (&cifs_tcp_ses_lock); + } +kfree (utf16_path); +kfree (dfs_req); +kfree (dfs_rsp); +return rc; +}#define SMB2_SYMLINK_STRUCT_SIZE \ (sizeof(struct smb2_err_rsp) - 1 + sizeof(struct smb2_symlink_err_rsp))
@@ -2263,6 +2359,7 @@ struct smb_version_operations smb20_operations = { .clone_range = smb2_clone_range, .wp_retry_size = smb2_wp_retry_size, .dir_needs_close = smb2_dir_needs_close, + .get_dfs_refer = smb2_get_dfs_refer, };struct smb_version_operations smb21_operations = {
@@ -2344,6 +2441,7 @@ struct smb_version_operations smb21_operations = { .wp_retry_size = smb2_wp_retry_size, .dir_needs_close = smb2_dir_needs_close, .enum_snapshots = smb3_enum_snapshots, + .get_dfs_refer = smb2_get_dfs_refer, };struct smb_version_operations smb30_operations = {
@@ -2435,6 +2533,7 @@ struct smb_version_operations smb30_operations = { .free_transform_rq = smb3_free_transform_rq, .is_transform_hdr = smb3_is_transform_hdr, .receive_transform = smb3_receive_transform, + .get_dfs_refer = smb2_get_dfs_refer, };#ifdef CONFIG_CIFS_SMB311
@@ -2527,6 +2626,7 @@ struct smb_version_operations smb311_operations = { .free_transform_rq = smb3_free_transform_rq, .is_transform_hdr = smb3_is_transform_hdr, .receive_transform = smb3_receive_transform, + .get_dfs_refer = smb2_get_dfs_refer, };#endif /* CIFS_SMB311 */
fs/cifs/smb2pdu.h +8 -0
@@ -695,6 +695,14 @@ struct fsctl_get_integrity_information_rsp {/* Integrity flags for above */ #define FSCTL_INTEGRITY_FLAG_CHECKSUM_ENFORCEMENT_OFF 0x00000001 +/* See MS-DFSC 2.2.2 */ +struct fsctl_get_dfs_referral_req { +__le16 MaxReferralLevel; +__u8 RequestFileName[]; +} __packed; + +/* DFS response is struct get_dfs_refer_rsp */ +/* See MS-SMB2 2.2.31.3 */ struct network_resiliency_req {__le32 Timeout;
Signature · 1 line
2.10.2
A message that is not in the archive (sent off-list or not yet received): 20170228184034.18771-8-aaptel-IBi9RG/[email protected]
Pavel Shilovsky
Reviewed-byRe: [PATCH v3 7/7] CIFS: implement get_dfs_refer for SMB2+
2017-02-28 10:40 GMT-08:00 Aurelien Aptel <aaptel-IBi9RG/[email protected]>:
Quoted 181 lines
in SMB2+ the
get_dfs_referoperation uses a FSCTL. The request can be made on any Tree Connection according to the specs. Since Samba only accepted it on an IPC connection until recently, try that first.https://lists.samba.org/archive/samba-technical/2017-February/118859.html
3.2.4.20.3 Application Requests DFS Referral Information:
Quoted 6 lines
The client MUST search for an existing Session and TreeConnect to any share on the server identified by ServerName for the user identified by UserCredentials. If no Session and TreeConnect are found, the client MUST establish a new Session and TreeConnect to IPC$ on the target server as described in section 3.2.4.2 using the supplied ServerName and UserCredentials.
Signed-off-by Aurelien Aptel <aaptel-IBi9RG/[email protected]>--- fs/cifs/smb2ops.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/smb2pdu.h | 8 +++++ 2 files changed, 108 insertions(+)fs/cifs/smb2ops.c +100
-0@@ -1104,6 +1104,102 @@ smb2_new_lease_key(struct cifs_fid *fid)generate_random_uuid (fid->lease_key); } +static int +smb2_get_dfs_refer (const unsigned int xid,struct cifs_ses *ses, +const char *search_name, +struct dfs_info3_param **target_nodes, +unsigned int *num_of_nodes, +const struct nls_table *nls_codepage,int remap) +{ +int rc; +__le16 *utf16_path =NULL ; +int utf16_path_len =0 ; +struct cifs_tcon *tcon; +struct fsctl_get_dfs_referral_req *dfs_req =NULL ; +struct get_dfs_referral_rsp *dfs_rsp =NULL ; +u32 dfs_req_size =0 , dfs_rsp_size =0 ; + +cifs_dbg (FYI ,"smb2_get_dfs_refer path <%s>\n" , search_name); + +/* +* Use any tcon from the current session. Here, the first one. +*/ +spin_lock (&cifs_tcp_ses_lock); + tcon = list_first_entry_or_null(&ses->tcon_list, struct cifs_tcon, tcon_list); +if (tcon) + tcon->tc_count++; +spin_unlock (&cifs_tcp_ses_lock); + +if (!tcon) { +cifs_dbg (VFS ,"session %p has no tcon available for a dfs referral request\n" , + ses); + rc = -ENOTCONN ; + goto out; + } + + utf16_path =cifs_strndup_to_utf16 (search_name,PATH_MAX , + &utf16_path_len, + nls_codepage, remap); +if (!utf16_path) { + rc = -ENOMEM ; + goto out; + } + + dfs_req_size =sizeof (*dfs_req) + utf16_path_len; + dfs_req =kzalloc (dfs_req_size,GFP_KERNEL ); +if (!dfs_req) { + rc = -ENOMEM ; + goto out; + } + +/* Highest DFS referral version understood */ + dfs_req->MaxReferralLevel =cpu_to_le16 (DFS_VERSION ); + +/* Path to resolve in an UTF-16 null-terminated string */ +memcpy (dfs_req->RequestFileName, utf16_path, utf16_path_len); + +do { +/* try first with IPC */ + rc =SMB2_ioctl (xid, tcon,NO_FILE_ID ,NO_FILE_ID , +FSCTL_DFS_GET_REFERRALS , + true/* is_fsctl */ , true/* use_ipc */ , + (char *)dfs_req, dfs_req_size, + (char **)&dfs_rsp, &dfs_rsp_size); +if (rc == -ENOTCONN ) { +/* try with normal tcon */ + rc =SMB2_ioctl (xid, tcon,NO_FILE_ID ,NO_FILE_ID , +FSCTL_DFS_GET_REFERRALS , + true/* is_fsctl */ , false/*use_ipc*/ , + (char *)dfs_req, dfs_req_size, + (char **)&dfs_rsp, &dfs_rsp_size); + } + }while (rc == -EAGAIN ); + +if (rc) { +cifs_dbg (VFS ,"ioctl error in smb2_get_dfs_refer rc=%d\n" , rc); + goto out; + } + + rc =parse_dfs_referrals (dfs_rsp, dfs_rsp_size, + num_of_nodes, target_nodes, + nls_codepage, remap, search_name, + true/* is_unicode */ ); +if (rc) { +cifs_dbg (VFS ,"parse error in smb2_get_dfs_refer rc=%d\n" , rc); + goto out; + } + + out: +if (tcon) { +spin_lock (&cifs_tcp_ses_lock); + tcon->tc_count--; +spin_unlock (&cifs_tcp_ses_lock); + } +kfree (utf16_path); +kfree (dfs_req); +kfree (dfs_rsp); +return rc; +}#define SMB2_SYMLINK_STRUCT_SIZE \ (sizeof(struct smb2_err_rsp) - 1 + sizeof(struct smb2_symlink_err_rsp))@@ -2263,6 +2359,7 @@ struct smb_version_operations smb20_operations = { .clone_range = smb2_clone_range, .wp_retry_size = smb2_wp_retry_size, .dir_needs_close = smb2_dir_needs_close, + .get_dfs_refer = smb2_get_dfs_refer, };struct smb_version_operations smb21_operations = {@@ -2344,6 +2441,7 @@ struct smb_version_operations smb21_operations = { .wp_retry_size = smb2_wp_retry_size, .dir_needs_close = smb2_dir_needs_close, .enum_snapshots = smb3_enum_snapshots, + .get_dfs_refer = smb2_get_dfs_refer, };struct smb_version_operations smb30_operations = {@@ -2435,6 +2533,7 @@ struct smb_version_operations smb30_operations = { .free_transform_rq = smb3_free_transform_rq, .is_transform_hdr = smb3_is_transform_hdr, .receive_transform = smb3_receive_transform, + .get_dfs_refer = smb2_get_dfs_refer, };#ifdef CONFIG_CIFS_SMB311 @@ -2527,6 +2626,7 @@ struct smb_version_operations smb311_operations = { .free_transform_rq = smb3_free_transform_rq, .is_transform_hdr = smb3_is_transform_hdr, .receive_transform = smb3_receive_transform, + .get_dfs_refer = smb2_get_dfs_refer, };#endif /* CIFS_SMB311 */ fs/cifs/smb2pdu.h +8
-1@@ -695,6 +695,14 @@ struct fsctl_get_integrity_information_rsp {/* Integrity flags for above */ #define FSCTL_INTEGRITY_FLAG_CHECKSUM_ENFORCEMENT_OFF 0x00000001 +/* See MS-DFSC 2.2.2 */ +struct fsctl_get_dfs_referral_req { +__le16 MaxReferralLevel; +__u8 RequestFileName[]; +} __packed; + +/* DFS response is struct get_dfs_refer_rsp */ +/* See MS-SMB2 2.2.31.3 */ struct network_resiliency_req {__le32 Timeout; --2.10.2
Quoted 4 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 2 lines
Best regards, Pavel Shilovsky
Re: [PATCH v3 7/7] CIFS: implement get_dfs_refer for SMB2+
In reply to a message not in the archive2017-02-28 10:40 GMT-08:00 Aurelien Aptel <aaptel-IBi9RG/[email protected]>:
Quoted 93 lines
in SMB2+ the
get_dfs_referoperation uses a FSCTL. The request can be made on any Tree Connection according to the specs. Since Samba only accepted it on an IPC connection until recently, try that first.https://lists.samba.org/archive/samba-technical/2017-February/118859.html
3.2.4.20.3 Application Requests DFS Referral Information:
Quoted 6 lines
The client MUST search for an existing Session and TreeConnect to any share on the server identified by ServerName for the user identified by UserCredentials. If no Session and TreeConnect are found, the client MUST establish a new Session and TreeConnect to IPC$ on the target server as described in section 3.2.4.2 using the supplied ServerName and UserCredentials.
Signed-off-by Aurelien Aptel <aaptel-IBi9RG/[email protected]>--- fs/cifs/smb2ops.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/smb2pdu.h | 8 +++++ 2 files changed, 108 insertions(+)fs/cifs/smb2ops.c +65
-0@@ -1104,6 +1104,102 @@ smb2_new_lease_key(struct cifs_fid *fid) generate_random_uuid(fid->lease_key); } +static int +smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses, + const char *search_name, + struct dfs_info3_param **target_nodes, + unsigned int *num_of_nodes, + const struct nls_table *nls_codepage, int remap) +{ + int rc; + __le16 *utf16_path = NULL; + int utf16_path_len = 0; + struct cifs_tcon *tcon; + struct fsctl_get_dfs_referral_req *dfs_req = NULL; + struct get_dfs_referral_rsp *dfs_rsp = NULL; + u32 dfs_req_size = 0, dfs_rsp_size = 0; + + cifs_dbg(FYI, "smb2_get_dfs_refer path <%s>\n", search_name); + + /* + * Use any tcon from the current session. Here, the first one. + */ + spin_lock(&cifs_tcp_ses_lock); + tcon = list_first_entry_or_null(&ses->tcon_list, struct cifs_tcon, tcon_list); + if (tcon) + tcon->tc_count++; + spin_unlock(&cifs_tcp_ses_lock); + + if (!tcon) { + cifs_dbg(VFS, "session %p has no tcon available for a dfs referral request\n", + ses); + rc = -ENOTCONN; + goto out; + } + + utf16_path = cifs_strndup_to_utf16(search_name, PATH_MAX, + &utf16_path_len, + nls_codepage, remap); + if (!utf16_path) { + rc = -ENOMEM; + goto out; + } + + dfs_req_size = sizeof(*dfs_req) + utf16_path_len; + dfs_req = kzalloc(dfs_req_size, GFP_KERNEL); + if (!dfs_req) { + rc = -ENOMEM; + goto out; + } + + /* Highest DFS referral version understood */ + dfs_req->MaxReferralLevel = cpu_to_le16(DFS_VERSION); + + /* Path to resolve in an UTF-16 null-terminated string */ + memcpy(dfs_req->RequestFileName, utf16_path, utf16_path_len); + + do { + /* try first with IPC */ + rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, + FSCTL_DFS_GET_REFERRALS, + true /* is_fsctl */, true /* use_ipc */, + (char *)dfs_req, dfs_req_size, + (char **)&dfs_rsp, &dfs_rsp_size); + if (rc == -ENOTCONN) { + /* try with normal tcon */ + rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, + FSCTL_DFS_GET_REFERRALS,
fs/cifs/smb2ops.c smb2_new_lease_key(struct cifs_fid *fid) · line 1181
Quoted 10 lines
fs/cifs/smb2ops.c +10
-0+ true/* is_fsctl */ , false/*use_ipc*/ , + (char *)dfs_req, dfs_req_size, + (char **)&dfs_rsp, &dfs_rsp_size); + } + }while (rc == -EAGAIN ); + +if (rc) { +cifs_dbg (VFS ,"ioctl error in smb2_get_dfs_refer rc=%d\n" , rc); + goto out; + }
During the local testing with cthon and xfstests with DFS is being involved I see a bunch of error messages like the one below:
CIFS VFS: ioctl error in smb2_get_dfs_refer rc=-2
Should we lower a debug level to FYI here?
--
Best regards,
Pavel Shilovsky
A message that is not in the archive (sent off-list or not yet received): CAKywueTx4b4+MDYeTm+jBsUZfmYe+Sa1HT9cUx-d4043hKxr+A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org
Re: [PATCH v3 7/7] CIFS: implement get_dfs_refer for SMB2+
2017-06-22 16:03 GMT-07:00 Pavel Shilovsky <[email protected]>:
Quoted 98 lines
2017-02-28 10:40 GMT-08:00 Aurelien Aptel <aaptel-IBi9RG/[email protected]>:
Quoted 97 lines
in SMB2+ the
get_dfs_referoperation uses a FSCTL. The request can be made on any Tree Connection according to the specs. Since Samba only accepted it on an IPC connection until recently, try that first.https://lists.samba.org/archive/samba-technical/2017-February/118859.html
3.2.4.20.3 Application Requests DFS Referral Information:
Quoted 6 lines
The client MUST search for an existing Session and TreeConnect to any share on the server identified by ServerName for the user identified by UserCredentials. If no Session and TreeConnect are found, the client MUST establish a new Session and TreeConnect to IPC$ on the target server as described in section 3.2.4.2 using the supplied ServerName and UserCredentials.
Signed-off-by Aurelien Aptel <aaptel-IBi9RG/[email protected]>--- fs/cifs/smb2ops.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/smb2pdu.h | 8 +++++ 2 files changed, 108 insertions(+)fs/cifs/smb2ops.c +69
-0@@ -1104,6 +1104,102 @@ smb2_new_lease_key(struct cifs_fid *fid)generate_random_uuid (fid->lease_key); } +static int +smb2_get_dfs_refer (const unsigned int xid,struct cifs_ses *ses, +const char *search_name, +struct dfs_info3_param **target_nodes, +unsigned int *num_of_nodes, +const struct nls_table *nls_codepage,int remap) +{ +int rc; +__le16 *utf16_path =NULL ; +int utf16_path_len =0 ; +struct cifs_tcon *tcon; +struct fsctl_get_dfs_referral_req *dfs_req =NULL ; +struct get_dfs_referral_rsp *dfs_rsp =NULL ; +u32 dfs_req_size =0 , dfs_rsp_size =0 ; + +cifs_dbg (FYI ,"smb2_get_dfs_refer path <%s>\n" , search_name); + +/* +* Use any tcon from the current session. Here, the first one. +*/ +spin_lock (&cifs_tcp_ses_lock); + tcon = list_first_entry_or_null(&ses->tcon_list, struct cifs_tcon, tcon_list); +if (tcon) + tcon->tc_count++; +spin_unlock (&cifs_tcp_ses_lock); + +if (!tcon) { +cifs_dbg (VFS ,"session %p has no tcon available for a dfs referral request\n" , + ses); + rc = -ENOTCONN ; + goto out; + } + + utf16_path =cifs_strndup_to_utf16 (search_name,PATH_MAX , + &utf16_path_len, + nls_codepage, remap); +if (!utf16_path) { + rc = -ENOMEM ; + goto out; + } + + dfs_req_size =sizeof (*dfs_req) + utf16_path_len; + dfs_req =kzalloc (dfs_req_size,GFP_KERNEL ); +if (!dfs_req) { + rc = -ENOMEM ; + goto out; + } + +/* Highest DFS referral version understood */ + dfs_req->MaxReferralLevel =cpu_to_le16 (DFS_VERSION ); + +/* Path to resolve in an UTF-16 null-terminated string */ +memcpy (dfs_req->RequestFileName, utf16_path, utf16_path_len); + + do { + /* try first with IPC */ + rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, + FSCTL_DFS_GET_REFERRALS, + true /* is_fsctl */, true /* use_ipc */, + (char *)dfs_req, dfs_req_size, + (char **)&dfs_rsp, &dfs_rsp_size); + if (rc == -ENOTCONN) { + /* try with normal tcon */ + rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, + FSCTL_DFS_GET_REFERRALS, + true /* is_fsctl */, false /*use_ipc*/, + (char *)dfs_req, dfs_req_size, + (char **)&dfs_rsp, &dfs_rsp_size); + }
Quoted 8 lines
fs/cifs/smb2ops.c smb2_new_lease_key(struct cifs_fid *fid) · line 1181
Quoted 6 lines
fs/cifs/smb2ops.c +6
-0+ }while (rc == -EAGAIN ); + +if (rc) { +cifs_dbg (VFS ,"ioctl error in smb2_get_dfs_refer rc=%d\n" , rc); + goto out; + }During the local testing with cthon and xfstests with DFS is being
^^^
Sorry, the above should be "without DFS being involved".
--
Best regards,
Pavel Shilovsky
A message that is not in the archive (sent off-list or not yet received): CAKywueSy1Y1PNLHkRnDbxgc+Kf1qe_H65DPkWpX-=k=Enu-VUw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org
Re: [PATCH v3 7/7] CIFS: implement get_dfs_refer for SMB2+
Hi Pavel,
Quoted 1 line · Pavel Shilovsky
Quoted 1 line
Should we lower a debug level to FYI here?
Sounds good.
Signature · 4 lines
Aurélien Aptel / SUSE Labs Samba Team GPG: 1839 CB5F 9F5B FB9B AA97 8C99 03C8 A49B 521B D5D3 SUSE Linux GmbH, Maxfeldstraße 5, 90409 Nürnberg, Germany GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
Merged v4 of this into cifs-2.6.git for-next
Quoted 101 lines · Aurelien Aptel
This series of patch tries to implement the
get_dfs_referoperation for SMB2+.In SMB2+, DFS resolving is now done through an FSCTL (patch #7). The relevant Microsoft specifications for this are:
MS-SMB2: 3.2.4.20 Application Requests an IO Control Code Operation
MS-SMB2: 3.2.4.20.3 Application Requests DFS Referral Information
MS-SMB2: 3.2.5.14 Receiving an SMB2 IOCTL Response
MS-SMB2: 3.2.5.14.4 Handling a DFS Referral Information ResponseMS-DFSC: 2.2 Message Syntax (but really the whole document is useful)
The DFS response payload however is identical. Patch #1 moves the DFS response parsing out of SMB1 code and makes it work on any version of SMB.
DFS code has 2 "main" entry points: initial mounting and automount (when a DFS link is accessed/traversed).
When automounting, cifs.ko calls
build_path_from_dentry()which only makes treename-prefixed paths when the tcon has theSMB_IN_DFS_SHARE. This flag is checked intcon->Flagswhich is never touched by SMB2 code as it setstcon->share_flagson connexion.* CIFS requires to prefix all pathnames with the treename prefix when connected to a DFS server, so the current
build_path_from_dentry()makes sense for CIFS.
* For SMB2+ it seems only the Create request requires the treename prefix. Simply making the function check for both CIFS SMB2+ flag for DFS to add a prefix does not work as the server has different expectations about which packet can have/require a DFS pathname.Patch #2 adds
build_path_from_dentry_optional_prefix()with an extra bool arg to decide to prefix or not. The automount code path always ask for it. Patch #6 modifiesSMB2_open()to add the treename prefix to the given path if the server requires it.We try to use an IPC connection first for the DFS request. Patch #3 adds a flag to
SMB2_ioctl()to force the usage ofipc_tid. The SMB2get_dfs_referoperation tries with the flag set and fallback to a share connection if that doesn't work.Patch #4 updates the type of
ipc_tidfrom u16 to u32 as that is what a Tid is in SMB2+. This is correct and really needed since in SMB2 Samba doesn't use sequential tree id but random ones in the 32bit space.As part of the mouting process a IPC tcon is made (I suspect we don't need it anymore in SMB3). This tcon doesn't respect the signing requirement. This is fixed by patch #5.
Finally the SMB2+ implementation of the
get_dfs_referraloperation is added in all supported SMB versions in patch #7.I've sucessfuly tested this (v1.0 and v3.0) against a Windows Server 2016 DFS setup and a Samba DFS setup.
Samba used to only accepts DFS referrals requests on an IPC connexion, which is in violation of the spec. A patch was sent on samba-technical and merged. It is not required anymore.
https://lists.samba.org/archive/samba-technical/2017-February/118859.html
Changes since v2:
* add
use_ipcflag toSMB2_open()
* makesmb2_get_dfs_refer()try IPC connections first
* usefirst_entry_or_null()instead offirst_entry()on the tcon list
* protect tcon list access with spinlock
* add inc/dec of the tcon reference number, protected by spinlockAurelien Aptel (7):
CIFS: move DFS response parsing out of SMB1 code
CIFS: addbuild_path_from_dentry_optional_prefix()
CIFS: adduse_ipcflag toSMB2_ioctl()
CIFS: letses->ipc_tidhold smb2 TreeIds
CIFS: set signing flag in SMB2+ TreeConnect if needed
CIFS: use DFS pathnames in SMB2+ Create requests
CIFS: implementget_dfs_referfor SMB2+fs/cifs/cifs_dfs_ref.c | 4 +- fs/cifs/cifsglob.h | 2 +- fs/cifs/cifspdu.h | 16 ++++--- fs/cifs/cifsproto.h | 7 +++ fs/cifs/cifssmb.c | 119 ++--------------------------------------------- fs/cifs/dir.c | 13 +++++- fs/cifs/misc.c | 105 +++++++++++++++++++++++++++++++++++++++++ fs/cifs/smb2file.c | 3 +- fs/cifs/smb2ops.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++--- fs/cifs/smb2pdu.c | 114 +++++++++++++++++++++++++++++++++++++-------- fs/cifs/smb2pdu.h | 8 ++++ fs/cifs/smb2proto.h | 3 +- 12 files changed, 365 insertions(+), 152 deletions(-)--
2.10.2--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 3 lines
Thanks, Steve