* [PATCH v3 0/7] Add support for DFS in SMB2+ @ 2017-02-28 18:40 Aurelien Aptel [not found] ` <20170228184034.18771-1-aaptel-IBi9RG/b67k@public.gmane.org> 0 siblings, 1 reply; 19+ messages in thread From: Aurelien Aptel @ 2017-02-28 18:40 UTC (permalink / raw) To: linux-cifs-u79uwXL29TY76Z2rM5mHXA; +Cc: Aurelien Aptel 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(-) -- 2.10.2 ^ permalink raw reply [flat|nested] 19+ messages in thread
[parent not found: <20170228184034.18771-1-aaptel-IBi9RG/b67k@public.gmane.org>]
* [PATCH v3 1/7] CIFS: move DFS response parsing out of SMB1 code [not found] ` <20170228184034.18771-1-aaptel-IBi9RG/b67k@public.gmane.org> @ 2017-02-28 18:40 ` Aurelien Aptel [not found] ` <20170228184034.18771-2-aaptel-IBi9RG/b67k@public.gmane.org> 2017-02-28 18:40 ` [PATCH v3 2/7] CIFS: add build_path_from_dentry_optional_prefix() Aurelien Aptel ` (6 subsequent siblings) 7 siblings, 1 reply; 19+ messages in thread From: Aurelien Aptel @ 2017-02-28 18:40 UTC (permalink / raw) To: linux-cifs-u79uwXL29TY76Z2rM5mHXA; +Cc: Aurelien Aptel 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). Signed-off-by: Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org> --- 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(-) diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index f5b8730..1ce733f 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -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 */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 406d2c1..c097830 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -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); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index f5099fb..5005c79 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -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); diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index c672915..d3fb115 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -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 ^ permalink raw reply related [flat|nested] 19+ messages in thread
[parent not found: <20170228184034.18771-2-aaptel-IBi9RG/b67k@public.gmane.org>]
* Re: [PATCH v3 1/7] CIFS: move DFS response parsing out of SMB1 code [not found] ` <20170228184034.18771-2-aaptel-IBi9RG/b67k@public.gmane.org> @ 2017-03-01 1:58 ` Pavel Shilovsky 0 siblings, 0 replies; 19+ messages in thread From: Pavel Shilovsky @ 2017-03-01 1:58 UTC (permalink / raw) To: Aurelien Aptel; +Cc: linux-cifs 2017-02-28 10:40 GMT-08:00 Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org>: > 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). > > Signed-off-by: Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org> > --- > 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(-) > > diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h > index f5b8730..1ce733f 100644 > --- a/fs/cifs/cifspdu.h > +++ b/fs/cifs/cifspdu.h > @@ -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 */ > diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h > index 406d2c1..c097830 100644 > --- a/fs/cifs/cifsproto.h > +++ b/fs/cifs/cifsproto.h > @@ -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); > diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c > index f5099fb..5005c79 100644 > --- a/fs/cifs/cifssmb.c > +++ b/fs/cifs/cifssmb.c > @@ -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); > diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c > index c672915..d3fb115 100644 > --- a/fs/cifs/misc.c > +++ b/fs/cifs/misc.c > @@ -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 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-cifs" in > the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org > More majordomo info at http://vger.kernel.org/majordomo-info.html Acked-by: Pavel Shilovsky <pshilov-0li6OtcxBFHby3iVrkZq2A@public.gmane.org> -- Best regards, Pavel Shilovsky ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 2/7] CIFS: add build_path_from_dentry_optional_prefix() [not found] ` <20170228184034.18771-1-aaptel-IBi9RG/b67k@public.gmane.org> 2017-02-28 18:40 ` [PATCH v3 1/7] CIFS: move DFS response parsing out of SMB1 code Aurelien Aptel @ 2017-02-28 18:40 ` Aurelien Aptel [not found] ` <20170228184034.18771-3-aaptel-IBi9RG/b67k@public.gmane.org> 2017-02-28 18:40 ` [PATCH v3 3/7] CIFS: add use_ipc flag to SMB2_ioctl() Aurelien Aptel ` (5 subsequent siblings) 7 siblings, 1 reply; 19+ messages in thread From: Aurelien Aptel @ 2017-02-28 18:40 UTC (permalink / raw) To: linux-cifs-u79uwXL29TY76Z2rM5mHXA; +Cc: Aurelien Aptel 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_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. Signed-off-by: Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org> --- fs/cifs/cifs_dfs_ref.c | 4 +++- fs/cifs/cifsproto.h | 2 ++ fs/cifs/dir.c | 13 ++++++++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index ec9dbbc..8a9ebfd 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -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; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index c097830..9ee46c1 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -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, diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 2c227a9..56366e9 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -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 ^ permalink raw reply related [flat|nested] 19+ messages in thread
[parent not found: <20170228184034.18771-3-aaptel-IBi9RG/b67k@public.gmane.org>]
* Re: [PATCH v3 2/7] CIFS: add build_path_from_dentry_optional_prefix() [not found] ` <20170228184034.18771-3-aaptel-IBi9RG/b67k@public.gmane.org> @ 2017-03-01 2:35 ` Pavel Shilovsky 0 siblings, 0 replies; 19+ messages in thread From: Pavel Shilovsky @ 2017-03-01 2:35 UTC (permalink / raw) To: Aurelien Aptel; +Cc: linux-cifs 2017-02-28 10:40 GMT-08:00 Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org>: > 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_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. > > Signed-off-by: Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org> > --- > fs/cifs/cifs_dfs_ref.c | 4 +++- > fs/cifs/cifsproto.h | 2 ++ > fs/cifs/dir.c | 13 ++++++++++++- > 3 files changed, 17 insertions(+), 2 deletions(-) > > diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c > index ec9dbbc..8a9ebfd 100644 > --- a/fs/cifs/cifs_dfs_ref.c > +++ b/fs/cifs/cifs_dfs_ref.c > @@ -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; > > diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h > index c097830..9ee46c1 100644 > --- a/fs/cifs/cifsproto.h > +++ b/fs/cifs/cifsproto.h > @@ -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, > diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c > index 2c227a9..56366e9 100644 > --- a/fs/cifs/dir.c > +++ b/fs/cifs/dir.c > @@ -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 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-cifs" in > the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org > More majordomo info at http://vger.kernel.org/majordomo-info.html Acked-by: Pavel Shilovsky <pshilov-0li6OtcxBFHby3iVrkZq2A@public.gmane.org> -- Best regards, Pavel Shilovsky ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 3/7] CIFS: add use_ipc flag to SMB2_ioctl() [not found] ` <20170228184034.18771-1-aaptel-IBi9RG/b67k@public.gmane.org> 2017-02-28 18:40 ` [PATCH v3 1/7] CIFS: move DFS response parsing out of SMB1 code Aurelien Aptel 2017-02-28 18:40 ` [PATCH v3 2/7] CIFS: add build_path_from_dentry_optional_prefix() Aurelien Aptel @ 2017-02-28 18:40 ` Aurelien Aptel [not found] ` <20170228184034.18771-4-aaptel-IBi9RG/b67k@public.gmane.org> 2017-02-28 18:40 ` [PATCH v3 4/7] CIFS: let ses->ipc_tid hold smb2 TreeIds Aurelien Aptel ` (4 subsequent siblings) 7 siblings, 1 reply; 19+ messages in thread From: Aurelien Aptel @ 2017-02-28 18:40 UTC (permalink / raw) To: linux-cifs-u79uwXL29TY76Z2rM5mHXA; +Cc: Aurelien Aptel when set, use the session IPC tree id instead of the tid in the provided tcon. Signed-off-by: Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org> --- 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(-) diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c index b2aff0c..b4b1f03 100644 --- a/fs/cifs/smb2file.c +++ b/fs/cifs/smb2file.c @@ -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) { diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index a44b4db..02937cc 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -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; diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index ad83b3d..8c4532d 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -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); diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 85fc7a7..11d9f30 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -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 ^ permalink raw reply related [flat|nested] 19+ messages in thread
[parent not found: <20170228184034.18771-4-aaptel-IBi9RG/b67k@public.gmane.org>]
* Re: [PATCH v3 3/7] CIFS: add use_ipc flag to SMB2_ioctl() [not found] ` <20170228184034.18771-4-aaptel-IBi9RG/b67k@public.gmane.org> @ 2017-03-01 2:36 ` Pavel Shilovsky 0 siblings, 0 replies; 19+ messages in thread From: Pavel Shilovsky @ 2017-03-01 2:36 UTC (permalink / raw) To: Aurelien Aptel; +Cc: linux-cifs 2017-02-28 10:40 GMT-08:00 Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org>: > when set, use the session IPC tree id instead of the tid in the provided > tcon. > > Signed-off-by: Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org> > --- > 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(-) > > diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c > index b2aff0c..b4b1f03 100644 > --- a/fs/cifs/smb2file.c > +++ b/fs/cifs/smb2file.c > @@ -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) { > diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c > index a44b4db..02937cc 100644 > --- a/fs/cifs/smb2ops.c > +++ b/fs/cifs/smb2ops.c > @@ -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; > diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c > index ad83b3d..8c4532d 100644 > --- a/fs/cifs/smb2pdu.c > +++ b/fs/cifs/smb2pdu.c > @@ -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); > > diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h > index 85fc7a7..11d9f30 100644 > --- a/fs/cifs/smb2proto.h > +++ b/fs/cifs/smb2proto.h > @@ -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 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-cifs" in > the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org > More majordomo info at http://vger.kernel.org/majordomo-info.html Reviewed-by: Pavel Shilovsky <pshilov-0li6OtcxBFHby3iVrkZq2A@public.gmane.org> -- Best regards, Pavel Shilovsky ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 4/7] CIFS: let ses->ipc_tid hold smb2 TreeIds [not found] ` <20170228184034.18771-1-aaptel-IBi9RG/b67k@public.gmane.org> ` (2 preceding siblings ...) 2017-02-28 18:40 ` [PATCH v3 3/7] CIFS: add use_ipc flag to SMB2_ioctl() Aurelien Aptel @ 2017-02-28 18:40 ` Aurelien Aptel [not found] ` <20170228184034.18771-5-aaptel-IBi9RG/b67k@public.gmane.org> 2017-02-28 18:40 ` [PATCH v3 5/7] CIFS: set signing flag in SMB2+ TreeConnect if needed Aurelien Aptel ` (3 subsequent siblings) 7 siblings, 1 reply; 19+ messages in thread From: Aurelien Aptel @ 2017-02-28 18:40 UTC (permalink / raw) To: linux-cifs-u79uwXL29TY76Z2rM5mHXA; +Cc: Aurelien Aptel the 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. Signed-off-by: Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org> --- fs/cifs/cifsglob.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 1a90bb3..af224cd 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -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 ^ permalink raw reply related [flat|nested] 19+ messages in thread
[parent not found: <20170228184034.18771-5-aaptel-IBi9RG/b67k@public.gmane.org>]
* Re: [PATCH v3 4/7] CIFS: let ses->ipc_tid hold smb2 TreeIds [not found] ` <20170228184034.18771-5-aaptel-IBi9RG/b67k@public.gmane.org> @ 2017-03-01 2:36 ` Pavel Shilovsky 0 siblings, 0 replies; 19+ messages in thread From: Pavel Shilovsky @ 2017-03-01 2:36 UTC (permalink / raw) To: Aurelien Aptel; +Cc: linux-cifs 2017-02-28 10:40 GMT-08:00 Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org>: > the 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. > > Signed-off-by: Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org> > --- > fs/cifs/cifsglob.h | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h > index 1a90bb3..af224cd 100644 > --- a/fs/cifs/cifsglob.h > +++ b/fs/cifs/cifsglob.h > @@ -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 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-cifs" in > the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org > More majordomo info at http://vger.kernel.org/majordomo-info.html Reviewed-by: Pavel Shilovsky <pshilov-0li6OtcxBFHby3iVrkZq2A@public.gmane.org> -- Best regards, Pavel Shilovsky ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 5/7] CIFS: set signing flag in SMB2+ TreeConnect if needed [not found] ` <20170228184034.18771-1-aaptel-IBi9RG/b67k@public.gmane.org> ` (3 preceding siblings ...) 2017-02-28 18:40 ` [PATCH v3 4/7] CIFS: let ses->ipc_tid hold smb2 TreeIds Aurelien Aptel @ 2017-02-28 18:40 ` Aurelien Aptel [not found] ` <20170228184034.18771-6-aaptel-IBi9RG/b67k@public.gmane.org> 2017-02-28 18:40 ` [PATCH v3 6/7] CIFS: use DFS pathnames in SMB2+ Create requests Aurelien Aptel ` (2 subsequent siblings) 7 siblings, 1 reply; 19+ messages in thread From: Aurelien Aptel @ 2017-02-28 18:40 UTC (permalink / raw) To: linux-cifs-u79uwXL29TY76Z2rM5mHXA; +Cc: Aurelien Aptel cifs_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. Signed-off-by: Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org> --- fs/cifs/smb2pdu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 8c4532d..2fd93ee 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -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 ^ permalink raw reply related [flat|nested] 19+ messages in thread
[parent not found: <20170228184034.18771-6-aaptel-IBi9RG/b67k@public.gmane.org>]
* Re: [PATCH v3 5/7] CIFS: set signing flag in SMB2+ TreeConnect if needed [not found] ` <20170228184034.18771-6-aaptel-IBi9RG/b67k@public.gmane.org> @ 2017-03-01 2:37 ` Pavel Shilovsky 0 siblings, 0 replies; 19+ messages in thread From: Pavel Shilovsky @ 2017-03-01 2:37 UTC (permalink / raw) To: Aurelien Aptel; +Cc: linux-cifs 2017-02-28 10:40 GMT-08:00 Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org>: > cifs_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. > > Signed-off-by: Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org> > --- > fs/cifs/smb2pdu.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c > index 8c4532d..2fd93ee 100644 > --- a/fs/cifs/smb2pdu.c > +++ b/fs/cifs/smb2pdu.c > @@ -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 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-cifs" in > the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org > More majordomo info at http://vger.kernel.org/majordomo-info.html Reviewed-by: Pavel Shilovsky <pshilov-0li6OtcxBFHby3iVrkZq2A@public.gmane.org> -- Best regards, Pavel Shilovsky ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 6/7] CIFS: use DFS pathnames in SMB2+ Create requests [not found] ` <20170228184034.18771-1-aaptel-IBi9RG/b67k@public.gmane.org> ` (4 preceding siblings ...) 2017-02-28 18:40 ` [PATCH v3 5/7] CIFS: set signing flag in SMB2+ TreeConnect if needed Aurelien Aptel @ 2017-02-28 18:40 ` Aurelien Aptel [not found] ` <20170228184034.18771-7-aaptel-IBi9RG/b67k@public.gmane.org> 2017-02-28 18:40 ` [PATCH v3 7/7] CIFS: implement get_dfs_refer for SMB2+ Aurelien Aptel 2017-03-02 4:41 ` [PATCH v3 0/7] Add support for DFS in SMB2+ Steve French 7 siblings, 1 reply; 19+ messages in thread From: Aurelien Aptel @ 2017-02-28 18:40 UTC (permalink / raw) To: linux-cifs-u79uwXL29TY76Z2rM5mHXA; +Cc: Aurelien Aptel 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-IBi9RG/b67k@public.gmane.org> --- fs/cifs/smb2pdu.c | 93 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 77 insertions(+), 16 deletions(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 2fd93ee..059da05 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -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 ^ permalink raw reply related [flat|nested] 19+ messages in thread
[parent not found: <20170228184034.18771-7-aaptel-IBi9RG/b67k@public.gmane.org>]
* Re: [PATCH v3 6/7] CIFS: use DFS pathnames in SMB2+ Create requests [not found] ` <20170228184034.18771-7-aaptel-IBi9RG/b67k@public.gmane.org> @ 2017-03-01 2:40 ` Pavel Shilovsky 0 siblings, 0 replies; 19+ messages in thread From: Pavel Shilovsky @ 2017-03-01 2:40 UTC (permalink / raw) To: Aurelien Aptel; +Cc: linux-cifs 2017-02-28 10:40 GMT-08:00 Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org>: > 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-IBi9RG/b67k@public.gmane.org> > --- > fs/cifs/smb2pdu.c | 93 +++++++++++++++++++++++++++++++++++++++++++++---------- > 1 file changed, 77 insertions(+), 16 deletions(-) > > diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c > index 2fd93ee..059da05 100644 > --- a/fs/cifs/smb2pdu.c > +++ b/fs/cifs/smb2pdu.c > @@ -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 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-cifs" in > the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org > More majordomo info at http://vger.kernel.org/majordomo-info.html Acked-by: Pavel Shilovsky <pshilov-0li6OtcxBFHby3iVrkZq2A@public.gmane.org> -- Best regards, Pavel Shilovsky ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 7/7] CIFS: implement get_dfs_refer for SMB2+ [not found] ` <20170228184034.18771-1-aaptel-IBi9RG/b67k@public.gmane.org> ` (5 preceding siblings ...) 2017-02-28 18:40 ` [PATCH v3 6/7] CIFS: use DFS pathnames in SMB2+ Create requests Aurelien Aptel @ 2017-02-28 18:40 ` Aurelien Aptel [not found] ` <20170228184034.18771-8-aaptel-IBi9RG/b67k@public.gmane.org> 2017-03-02 4:41 ` [PATCH v3 0/7] Add support for DFS in SMB2+ Steve French 7 siblings, 1 reply; 19+ messages in thread From: Aurelien Aptel @ 2017-02-28 18:40 UTC (permalink / raw) To: linux-cifs-u79uwXL29TY76Z2rM5mHXA; +Cc: Aurelien Aptel in 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: > 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/b67k@public.gmane.org> --- fs/cifs/smb2ops.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/smb2pdu.h | 8 +++++ 2 files changed, 108 insertions(+) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 02937cc..fcd524d 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -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 */ diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index c03b252..18700fd 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -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 ^ permalink raw reply related [flat|nested] 19+ messages in thread
[parent not found: <20170228184034.18771-8-aaptel-IBi9RG/b67k@public.gmane.org>]
* Re: [PATCH v3 7/7] CIFS: implement get_dfs_refer for SMB2+ [not found] ` <20170228184034.18771-8-aaptel-IBi9RG/b67k@public.gmane.org> @ 2017-03-01 2:42 ` Pavel Shilovsky 2017-06-22 23:03 ` Pavel Shilovsky 1 sibling, 0 replies; 19+ messages in thread From: Pavel Shilovsky @ 2017-03-01 2:42 UTC (permalink / raw) To: Aurelien Aptel; +Cc: linux-cifs 2017-02-28 10:40 GMT-08:00 Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org>: > in 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: >> 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/b67k@public.gmane.org> > --- > fs/cifs/smb2ops.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > fs/cifs/smb2pdu.h | 8 +++++ > 2 files changed, 108 insertions(+) > > diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c > index 02937cc..fcd524d 100644 > --- a/fs/cifs/smb2ops.c > +++ b/fs/cifs/smb2ops.c > @@ -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 */ > > diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h > index c03b252..18700fd 100644 > --- a/fs/cifs/smb2pdu.h > +++ b/fs/cifs/smb2pdu.h > @@ -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 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-cifs" in > the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org > More majordomo info at http://vger.kernel.org/majordomo-info.html Reviewed-by: Pavel Shilovsky <pshilov-0li6OtcxBFHby3iVrkZq2A@public.gmane.org> -- Best regards, Pavel Shilovsky ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 7/7] CIFS: implement get_dfs_refer for SMB2+ [not found] ` <20170228184034.18771-8-aaptel-IBi9RG/b67k@public.gmane.org> 2017-03-01 2:42 ` Pavel Shilovsky @ 2017-06-22 23:03 ` Pavel Shilovsky [not found] ` <CAKywueTx4b4+MDYeTm+jBsUZfmYe+Sa1HT9cUx-d4043hKxr+A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 1 sibling, 1 reply; 19+ messages in thread From: Pavel Shilovsky @ 2017-06-22 23:03 UTC (permalink / raw) To: Aurelien Aptel; +Cc: linux-cifs 2017-02-28 10:40 GMT-08:00 Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org>: > in 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: >> 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/b67k@public.gmane.org> > --- > fs/cifs/smb2ops.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > fs/cifs/smb2pdu.h | 8 +++++ > 2 files changed, 108 insertions(+) > > diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c > index 02937cc..fcd524d 100644 > --- a/fs/cifs/smb2ops.c > +++ b/fs/cifs/smb2ops.c > @@ -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; > + } 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 ^ permalink raw reply [flat|nested] 19+ messages in thread
[parent not found: <CAKywueTx4b4+MDYeTm+jBsUZfmYe+Sa1HT9cUx-d4043hKxr+A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH v3 7/7] CIFS: implement get_dfs_refer for SMB2+ [not found] ` <CAKywueTx4b4+MDYeTm+jBsUZfmYe+Sa1HT9cUx-d4043hKxr+A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2017-06-22 23:05 ` Pavel Shilovsky [not found] ` <CAKywueSy1Y1PNLHkRnDbxgc+Kf1qe_H65DPkWpX-=k=Enu-VUw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 19+ messages in thread From: Pavel Shilovsky @ 2017-06-22 23:05 UTC (permalink / raw) To: Aurelien Aptel; +Cc: linux-cifs 2017-06-22 16:03 GMT-07:00 Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>: > 2017-02-28 10:40 GMT-08:00 Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org>: >> in 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: >>> 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/b67k@public.gmane.org> >> --- >> fs/cifs/smb2ops.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ >> fs/cifs/smb2pdu.h | 8 +++++ >> 2 files changed, 108 insertions(+) >> >> diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c >> index 02937cc..fcd524d 100644 >> --- a/fs/cifs/smb2ops.c >> +++ b/fs/cifs/smb2ops.c >> @@ -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; >> + } > > 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 ^ permalink raw reply [flat|nested] 19+ messages in thread
[parent not found: <CAKywueSy1Y1PNLHkRnDbxgc+Kf1qe_H65DPkWpX-=k=Enu-VUw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH v3 7/7] CIFS: implement get_dfs_refer for SMB2+ [not found] ` <CAKywueSy1Y1PNLHkRnDbxgc+Kf1qe_H65DPkWpX-=k=Enu-VUw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2017-06-23 9:19 ` Aurélien Aptel 0 siblings, 0 replies; 19+ messages in thread From: Aurélien Aptel @ 2017-06-23 9:19 UTC (permalink / raw) To: Pavel Shilovsky; +Cc: linux-cifs Hi Pavel, Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes: >> Should we lower a debug level to FYI here? Sounds good. -- 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) ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 0/7] Add support for DFS in SMB2+ [not found] ` <20170228184034.18771-1-aaptel-IBi9RG/b67k@public.gmane.org> ` (6 preceding siblings ...) 2017-02-28 18:40 ` [PATCH v3 7/7] CIFS: implement get_dfs_refer for SMB2+ Aurelien Aptel @ 2017-03-02 4:41 ` Steve French 7 siblings, 0 replies; 19+ messages in thread From: Steve French @ 2017-03-02 4:41 UTC (permalink / raw) To: Aurelien Aptel; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA Merged v4 of this into cifs-2.6.git for-next On Tue, Feb 28, 2017 at 12:40 PM, Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org> wrote: > 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(-) > > -- > 2.10.2 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-cifs" in > the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- Thanks, Steve ^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2017-06-23 9:19 UTC | newest] Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2017-02-28 18:40 [PATCH v3 0/7] Add support for DFS in SMB2+ Aurelien Aptel [not found] ` <20170228184034.18771-1-aaptel-IBi9RG/b67k@public.gmane.org> 2017-02-28 18:40 ` [PATCH v3 1/7] CIFS: move DFS response parsing out of SMB1 code Aurelien Aptel [not found] ` <20170228184034.18771-2-aaptel-IBi9RG/b67k@public.gmane.org> 2017-03-01 1:58 ` Pavel Shilovsky 2017-02-28 18:40 ` [PATCH v3 2/7] CIFS: add build_path_from_dentry_optional_prefix() Aurelien Aptel [not found] ` <20170228184034.18771-3-aaptel-IBi9RG/b67k@public.gmane.org> 2017-03-01 2:35 ` Pavel Shilovsky 2017-02-28 18:40 ` [PATCH v3 3/7] CIFS: add use_ipc flag to SMB2_ioctl() Aurelien Aptel [not found] ` <20170228184034.18771-4-aaptel-IBi9RG/b67k@public.gmane.org> 2017-03-01 2:36 ` Pavel Shilovsky 2017-02-28 18:40 ` [PATCH v3 4/7] CIFS: let ses->ipc_tid hold smb2 TreeIds Aurelien Aptel [not found] ` <20170228184034.18771-5-aaptel-IBi9RG/b67k@public.gmane.org> 2017-03-01 2:36 ` Pavel Shilovsky 2017-02-28 18:40 ` [PATCH v3 5/7] CIFS: set signing flag in SMB2+ TreeConnect if needed Aurelien Aptel [not found] ` <20170228184034.18771-6-aaptel-IBi9RG/b67k@public.gmane.org> 2017-03-01 2:37 ` Pavel Shilovsky 2017-02-28 18:40 ` [PATCH v3 6/7] CIFS: use DFS pathnames in SMB2+ Create requests Aurelien Aptel [not found] ` <20170228184034.18771-7-aaptel-IBi9RG/b67k@public.gmane.org> 2017-03-01 2:40 ` Pavel Shilovsky 2017-02-28 18:40 ` [PATCH v3 7/7] CIFS: implement get_dfs_refer for SMB2+ Aurelien Aptel [not found] ` <20170228184034.18771-8-aaptel-IBi9RG/b67k@public.gmane.org> 2017-03-01 2:42 ` Pavel Shilovsky 2017-06-22 23:03 ` Pavel Shilovsky [not found] ` <CAKywueTx4b4+MDYeTm+jBsUZfmYe+Sa1HT9cUx-d4043hKxr+A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2017-06-22 23:05 ` Pavel Shilovsky [not found] ` <CAKywueSy1Y1PNLHkRnDbxgc+Kf1qe_H65DPkWpX-=k=Enu-VUw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2017-06-23 9:19 ` Aurélien Aptel 2017-03-02 4:41 ` [PATCH v3 0/7] Add support for DFS in SMB2+ Steve French
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.