diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-03-03 19:00:59 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-03-03 19:00:59 -0500 |
commit | 0a040b2113ec226bcf56fcbe02d035bb5b30c35e (patch) | |
tree | 2e2b8908640ffce4b474802134a18412a23b180d /fs | |
parent | 4e66c42c60fdf9be81837857454a41b39bf1b773 (diff) | |
parent | ef65aaede23f75977af56a8c330bb9be8c6e125c (diff) |
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
Pull SMB3 fixes from Steve French:
"Some small bug fixes as well as SMB2.1/SMB3 enablement for DFS (global
namespace) which previously was only enabled for CIFS"
* 'for-next' of git://git.samba.org/sfrench/cifs-2.6:
smb2: Enforce sec= mount option
CIFS: Fix sparse warnings
CIFS: implement get_dfs_refer for SMB2+
CIFS: use DFS pathnames in SMB2+ Create requests
CIFS: set signing flag in SMB2+ TreeConnect if needed
CIFS: let ses->ipc_tid hold smb2 TreeIds
CIFS: add use_ipc flag to SMB2_ioctl()
CIFS: add build_path_from_dentry_optional_prefix()
CIFS: move DFS response parsing out of SMB1 code
CIFS: Fix possible use after free in demultiplex thread
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cifs/cifs_dfs_ref.c | 4 | ||||
-rw-r--r-- | fs/cifs/cifs_unicode.h | 6 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 5 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 16 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 9 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 119 | ||||
-rw-r--r-- | fs/cifs/connect.c | 3 | ||||
-rw-r--r-- | fs/cifs/dir.c | 13 | ||||
-rw-r--r-- | fs/cifs/misc.c | 105 | ||||
-rw-r--r-- | fs/cifs/sess.c | 4 | ||||
-rw-r--r-- | fs/cifs/smb1ops.c | 1 | ||||
-rw-r--r-- | fs/cifs/smb2file.c | 3 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 160 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 154 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.h | 8 | ||||
-rw-r--r-- | fs/cifs/smb2proto.h | 5 |
16 files changed, 447 insertions, 168 deletions
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index 9156be545b0f..6b61df117fd4 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
@@ -303,7 +303,9 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt) | |||
303 | * gives us the latter, so we must adjust the result. | 303 | * gives us the latter, so we must adjust the result. |
304 | */ | 304 | */ |
305 | mnt = ERR_PTR(-ENOMEM); | 305 | mnt = ERR_PTR(-ENOMEM); |
306 | full_path = build_path_from_dentry(mntpt); | 306 | |
307 | /* always use tree name prefix */ | ||
308 | full_path = build_path_from_dentry_optional_prefix(mntpt, true); | ||
307 | if (full_path == NULL) | 309 | if (full_path == NULL) |
308 | goto cdda_exit; | 310 | goto cdda_exit; |
309 | 311 | ||
diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h index 479bc0a941f3..3d7298cc0aeb 100644 --- a/fs/cifs/cifs_unicode.h +++ b/fs/cifs/cifs_unicode.h | |||
@@ -130,10 +130,10 @@ wchar_t cifs_toupper(wchar_t in); | |||
130 | * Returns: | 130 | * Returns: |
131 | * Address of the first string | 131 | * Address of the first string |
132 | */ | 132 | */ |
133 | static inline wchar_t * | 133 | static inline __le16 * |
134 | UniStrcat(wchar_t *ucs1, const wchar_t *ucs2) | 134 | UniStrcat(__le16 *ucs1, const __le16 *ucs2) |
135 | { | 135 | { |
136 | wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */ | 136 | __le16 *anchor = ucs1; /* save a pointer to start of ucs1 */ |
137 | 137 | ||
138 | while (*ucs1++) ; /* To end of first string */ | 138 | while (*ucs1++) ; /* To end of first string */ |
139 | ucs1--; /* Return to the null */ | 139 | ucs1--; /* Return to the null */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 1a90bb3e2986..d42dd3288647 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -443,6 +443,9 @@ struct smb_version_operations { | |||
443 | int (*is_transform_hdr)(void *buf); | 443 | int (*is_transform_hdr)(void *buf); |
444 | int (*receive_transform)(struct TCP_Server_Info *, | 444 | int (*receive_transform)(struct TCP_Server_Info *, |
445 | struct mid_q_entry **); | 445 | struct mid_q_entry **); |
446 | enum securityEnum (*select_sectype)(struct TCP_Server_Info *, | ||
447 | enum securityEnum); | ||
448 | |||
446 | }; | 449 | }; |
447 | 450 | ||
448 | struct smb_version_values { | 451 | struct smb_version_values { |
@@ -822,7 +825,7 @@ struct cifs_ses { | |||
822 | int ses_count; /* reference counter */ | 825 | int ses_count; /* reference counter */ |
823 | enum statusEnum status; | 826 | enum statusEnum status; |
824 | unsigned overrideSecFlg; /* if non-zero override global sec flags */ | 827 | unsigned overrideSecFlg; /* if non-zero override global sec flags */ |
825 | __u16 ipc_tid; /* special tid for connection to IPC share */ | 828 | __u32 ipc_tid; /* special tid for connection to IPC share */ |
826 | char *serverOS; /* name of operating system underlying server */ | 829 | char *serverOS; /* name of operating system underlying server */ |
827 | char *serverNOS; /* name of network operating system of server */ | 830 | char *serverNOS; /* name of network operating system of server */ |
828 | char *serverDomain; /* security realm of server */ | 831 | char *serverDomain; /* security realm of server */ |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index f5b87303ce46..1ce733f3582f 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 */ | |||
2086 | __u8 ServiceSiteGuid[16]; /* MBZ, ignored */ | 2086 | __u8 ServiceSiteGuid[16]; /* MBZ, ignored */ |
2087 | } __attribute__((packed)) REFERRAL3; | 2087 | } __attribute__((packed)) REFERRAL3; |
2088 | 2088 | ||
2089 | typedef struct smb_com_transaction_get_dfs_refer_rsp { | 2089 | struct get_dfs_referral_rsp { |
2090 | struct smb_hdr hdr; /* wct = 10 */ | ||
2091 | struct trans2_resp t2; | ||
2092 | __u16 ByteCount; | ||
2093 | __u8 Pad; | ||
2094 | __le16 PathConsumed; | 2090 | __le16 PathConsumed; |
2095 | __le16 NumberOfReferrals; | 2091 | __le16 NumberOfReferrals; |
2096 | __le32 DFSFlags; | 2092 | __le32 DFSFlags; |
2097 | REFERRAL3 referrals[1]; /* array of level 3 dfs_referral structures */ | 2093 | REFERRAL3 referrals[1]; /* array of level 3 dfs_referral structures */ |
2098 | /* followed by the strings pointed to by the referral structures */ | 2094 | /* followed by the strings pointed to by the referral structures */ |
2099 | } __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_RSP; | 2095 | } __packed; |
2096 | |||
2097 | typedef struct smb_com_transaction_get_dfs_refer_rsp { | ||
2098 | struct smb_hdr hdr; /* wct = 10 */ | ||
2099 | struct trans2_resp t2; | ||
2100 | __u16 ByteCount; | ||
2101 | __u8 Pad; | ||
2102 | struct get_dfs_referral_rsp dfs_data; | ||
2103 | } __packed TRANSACTION2_GET_DFS_REFER_RSP; | ||
2100 | 2104 | ||
2101 | /* DFS Flags */ | 2105 | /* DFS Flags */ |
2102 | #define DFSREF_REFERRAL_SERVER 0x00000001 /* all targets are DFS roots */ | 2106 | #define DFSREF_REFERRAL_SERVER 0x00000001 /* all targets are DFS roots */ |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 406d2c10ba78..97e5d236d265 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -61,6 +61,8 @@ extern void exit_cifs_idmap(void); | |||
61 | extern int init_cifs_spnego(void); | 61 | extern int init_cifs_spnego(void); |
62 | extern void exit_cifs_spnego(void); | 62 | extern void exit_cifs_spnego(void); |
63 | extern char *build_path_from_dentry(struct dentry *); | 63 | extern char *build_path_from_dentry(struct dentry *); |
64 | extern char *build_path_from_dentry_optional_prefix(struct dentry *direntry, | ||
65 | bool prefix); | ||
64 | extern char *cifs_build_path_to_root(struct smb_vol *vol, | 66 | extern char *cifs_build_path_to_root(struct smb_vol *vol, |
65 | struct cifs_sb_info *cifs_sb, | 67 | struct cifs_sb_info *cifs_sb, |
66 | struct cifs_tcon *tcon, | 68 | struct cifs_tcon *tcon, |
@@ -284,6 +286,11 @@ extern int get_dfs_path(const unsigned int xid, struct cifs_ses *ses, | |||
284 | const struct nls_table *nls_codepage, | 286 | const struct nls_table *nls_codepage, |
285 | unsigned int *num_referrals, | 287 | unsigned int *num_referrals, |
286 | struct dfs_info3_param **referrals, int remap); | 288 | struct dfs_info3_param **referrals, int remap); |
289 | extern int parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, | ||
290 | unsigned int *num_of_nodes, | ||
291 | struct dfs_info3_param **target_nodes, | ||
292 | const struct nls_table *nls_codepage, int remap, | ||
293 | const char *searchName, bool is_unicode); | ||
287 | extern void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon, | 294 | extern void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon, |
288 | struct cifs_sb_info *cifs_sb, | 295 | struct cifs_sb_info *cifs_sb, |
289 | struct smb_vol *vol); | 296 | struct smb_vol *vol); |
@@ -526,4 +533,6 @@ int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, | |||
526 | int __cifs_calc_signature(struct smb_rqst *rqst, | 533 | int __cifs_calc_signature(struct smb_rqst *rqst, |
527 | struct TCP_Server_Info *server, char *signature, | 534 | struct TCP_Server_Info *server, char *signature, |
528 | struct shash_desc *shash); | 535 | struct shash_desc *shash); |
536 | enum securityEnum cifs_select_sectype(struct TCP_Server_Info *, | ||
537 | enum securityEnum); | ||
529 | #endif /* _CIFSPROTO_H */ | 538 | #endif /* _CIFSPROTO_H */ |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index f5099fb8a22f..066950671929 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -4786,117 +4786,6 @@ GetInodeNumOut: | |||
4786 | return rc; | 4786 | return rc; |
4787 | } | 4787 | } |
4788 | 4788 | ||
4789 | /* parses DFS refferal V3 structure | ||
4790 | * caller is responsible for freeing target_nodes | ||
4791 | * returns: | ||
4792 | * on success - 0 | ||
4793 | * on failure - errno | ||
4794 | */ | ||
4795 | static int | ||
4796 | parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, | ||
4797 | unsigned int *num_of_nodes, | ||
4798 | struct dfs_info3_param **target_nodes, | ||
4799 | const struct nls_table *nls_codepage, int remap, | ||
4800 | const char *searchName) | ||
4801 | { | ||
4802 | int i, rc = 0; | ||
4803 | char *data_end; | ||
4804 | bool is_unicode; | ||
4805 | struct dfs_referral_level_3 *ref; | ||
4806 | |||
4807 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) | ||
4808 | is_unicode = true; | ||
4809 | else | ||
4810 | is_unicode = false; | ||
4811 | *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals); | ||
4812 | |||
4813 | if (*num_of_nodes < 1) { | ||
4814 | cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n", | ||
4815 | *num_of_nodes); | ||
4816 | rc = -EINVAL; | ||
4817 | goto parse_DFS_referrals_exit; | ||
4818 | } | ||
4819 | |||
4820 | ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals); | ||
4821 | if (ref->VersionNumber != cpu_to_le16(3)) { | ||
4822 | cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n", | ||
4823 | le16_to_cpu(ref->VersionNumber)); | ||
4824 | rc = -EINVAL; | ||
4825 | goto parse_DFS_referrals_exit; | ||
4826 | } | ||
4827 | |||
4828 | /* get the upper boundary of the resp buffer */ | ||
4829 | data_end = (char *)(&(pSMBr->PathConsumed)) + | ||
4830 | le16_to_cpu(pSMBr->t2.DataCount); | ||
4831 | |||
4832 | cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n", | ||
4833 | *num_of_nodes, le32_to_cpu(pSMBr->DFSFlags)); | ||
4834 | |||
4835 | *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param), | ||
4836 | GFP_KERNEL); | ||
4837 | if (*target_nodes == NULL) { | ||
4838 | rc = -ENOMEM; | ||
4839 | goto parse_DFS_referrals_exit; | ||
4840 | } | ||
4841 | |||
4842 | /* collect necessary data from referrals */ | ||
4843 | for (i = 0; i < *num_of_nodes; i++) { | ||
4844 | char *temp; | ||
4845 | int max_len; | ||
4846 | struct dfs_info3_param *node = (*target_nodes)+i; | ||
4847 | |||
4848 | node->flags = le32_to_cpu(pSMBr->DFSFlags); | ||
4849 | if (is_unicode) { | ||
4850 | __le16 *tmp = kmalloc(strlen(searchName)*2 + 2, | ||
4851 | GFP_KERNEL); | ||
4852 | if (tmp == NULL) { | ||
4853 | rc = -ENOMEM; | ||
4854 | goto parse_DFS_referrals_exit; | ||
4855 | } | ||
4856 | cifsConvertToUTF16((__le16 *) tmp, searchName, | ||
4857 | PATH_MAX, nls_codepage, remap); | ||
4858 | node->path_consumed = cifs_utf16_bytes(tmp, | ||
4859 | le16_to_cpu(pSMBr->PathConsumed), | ||
4860 | nls_codepage); | ||
4861 | kfree(tmp); | ||
4862 | } else | ||
4863 | node->path_consumed = le16_to_cpu(pSMBr->PathConsumed); | ||
4864 | |||
4865 | node->server_type = le16_to_cpu(ref->ServerType); | ||
4866 | node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags); | ||
4867 | |||
4868 | /* copy DfsPath */ | ||
4869 | temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset); | ||
4870 | max_len = data_end - temp; | ||
4871 | node->path_name = cifs_strndup_from_utf16(temp, max_len, | ||
4872 | is_unicode, nls_codepage); | ||
4873 | if (!node->path_name) { | ||
4874 | rc = -ENOMEM; | ||
4875 | goto parse_DFS_referrals_exit; | ||
4876 | } | ||
4877 | |||
4878 | /* copy link target UNC */ | ||
4879 | temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset); | ||
4880 | max_len = data_end - temp; | ||
4881 | node->node_name = cifs_strndup_from_utf16(temp, max_len, | ||
4882 | is_unicode, nls_codepage); | ||
4883 | if (!node->node_name) { | ||
4884 | rc = -ENOMEM; | ||
4885 | goto parse_DFS_referrals_exit; | ||
4886 | } | ||
4887 | |||
4888 | ref++; | ||
4889 | } | ||
4890 | |||
4891 | parse_DFS_referrals_exit: | ||
4892 | if (rc) { | ||
4893 | free_dfs_info_array(*target_nodes, *num_of_nodes); | ||
4894 | *target_nodes = NULL; | ||
4895 | *num_of_nodes = 0; | ||
4896 | } | ||
4897 | return rc; | ||
4898 | } | ||
4899 | |||
4900 | int | 4789 | int |
4901 | CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses, | 4790 | CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses, |
4902 | const char *search_name, struct dfs_info3_param **target_nodes, | 4791 | const char *search_name, struct dfs_info3_param **target_nodes, |
@@ -4993,9 +4882,11 @@ getDFSRetry: | |||
4993 | get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset)); | 4882 | get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset)); |
4994 | 4883 | ||
4995 | /* parse returned result into more usable form */ | 4884 | /* parse returned result into more usable form */ |
4996 | rc = parse_DFS_referrals(pSMBr, num_of_nodes, | 4885 | rc = parse_dfs_referrals(&pSMBr->dfs_data, |
4997 | target_nodes, nls_codepage, remap, | 4886 | le16_to_cpu(pSMBr->t2.DataCount), |
4998 | search_name); | 4887 | num_of_nodes, target_nodes, nls_codepage, |
4888 | remap, search_name, | ||
4889 | (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0); | ||
4999 | 4890 | ||
5000 | GetDFSRefExit: | 4891 | GetDFSRefExit: |
5001 | cifs_buf_release(pSMB); | 4892 | cifs_buf_release(pSMB); |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 3aa457f83214..9ae695ae3ed7 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -2074,7 +2074,8 @@ match_security(struct TCP_Server_Info *server, struct smb_vol *vol) | |||
2074 | * that was specified, or "Unspecified" if that sectype was not | 2074 | * that was specified, or "Unspecified" if that sectype was not |
2075 | * compatible with the given NEGOTIATE request. | 2075 | * compatible with the given NEGOTIATE request. |
2076 | */ | 2076 | */ |
2077 | if (select_sectype(server, vol->sectype) == Unspecified) | 2077 | if (server->ops->select_sectype(server, vol->sectype) |
2078 | == Unspecified) | ||
2078 | return false; | 2079 | return false; |
2079 | 2080 | ||
2080 | /* | 2081 | /* |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 2c227a99f369..56366e984076 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, | |||
81 | char * | 81 | char * |
82 | build_path_from_dentry(struct dentry *direntry) | 82 | build_path_from_dentry(struct dentry *direntry) |
83 | { | 83 | { |
84 | struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); | ||
85 | struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); | ||
86 | bool prefix = tcon->Flags & SMB_SHARE_IS_IN_DFS; | ||
87 | |||
88 | return build_path_from_dentry_optional_prefix(direntry, | ||
89 | prefix); | ||
90 | } | ||
91 | |||
92 | char * | ||
93 | build_path_from_dentry_optional_prefix(struct dentry *direntry, bool prefix) | ||
94 | { | ||
84 | struct dentry *temp; | 95 | struct dentry *temp; |
85 | int namelen; | 96 | int namelen; |
86 | int dfsplen; | 97 | int dfsplen; |
@@ -92,7 +103,7 @@ build_path_from_dentry(struct dentry *direntry) | |||
92 | unsigned seq; | 103 | unsigned seq; |
93 | 104 | ||
94 | dirsep = CIFS_DIR_SEP(cifs_sb); | 105 | dirsep = CIFS_DIR_SEP(cifs_sb); |
95 | if (tcon->Flags & SMB_SHARE_IS_IN_DFS) | 106 | if (prefix) |
96 | dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1); | 107 | dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1); |
97 | else | 108 | else |
98 | dfsplen = 0; | 109 | dfsplen = 0; |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index c6729156f9a0..d3fb11529ed9 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, | |||
640 | cifs_add_pending_open_locked(fid, tlink, open); | 640 | cifs_add_pending_open_locked(fid, tlink, open); |
641 | spin_unlock(&tlink_tcon(open->tlink)->open_file_lock); | 641 | spin_unlock(&tlink_tcon(open->tlink)->open_file_lock); |
642 | } | 642 | } |
643 | |||
644 | /* parses DFS refferal V3 structure | ||
645 | * caller is responsible for freeing target_nodes | ||
646 | * returns: | ||
647 | * - on success - 0 | ||
648 | * - on failure - errno | ||
649 | */ | ||
650 | int | ||
651 | parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, | ||
652 | unsigned int *num_of_nodes, | ||
653 | struct dfs_info3_param **target_nodes, | ||
654 | const struct nls_table *nls_codepage, int remap, | ||
655 | const char *searchName, bool is_unicode) | ||
656 | { | ||
657 | int i, rc = 0; | ||
658 | char *data_end; | ||
659 | struct dfs_referral_level_3 *ref; | ||
660 | |||
661 | *num_of_nodes = le16_to_cpu(rsp->NumberOfReferrals); | ||
662 | |||
663 | if (*num_of_nodes < 1) { | ||
664 | cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n", | ||
665 | *num_of_nodes); | ||
666 | rc = -EINVAL; | ||
667 | goto parse_DFS_referrals_exit; | ||
668 | } | ||
669 | |||
670 | ref = (struct dfs_referral_level_3 *) &(rsp->referrals); | ||
671 | if (ref->VersionNumber != cpu_to_le16(3)) { | ||
672 | cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n", | ||
673 | le16_to_cpu(ref->VersionNumber)); | ||
674 | rc = -EINVAL; | ||
675 | goto parse_DFS_referrals_exit; | ||
676 | } | ||
677 | |||
678 | /* get the upper boundary of the resp buffer */ | ||
679 | data_end = (char *)rsp + rsp_size; | ||
680 | |||
681 | cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n", | ||
682 | *num_of_nodes, le32_to_cpu(rsp->DFSFlags)); | ||
683 | |||
684 | *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param), | ||
685 | GFP_KERNEL); | ||
686 | if (*target_nodes == NULL) { | ||
687 | rc = -ENOMEM; | ||
688 | goto parse_DFS_referrals_exit; | ||
689 | } | ||
690 | |||
691 | /* collect necessary data from referrals */ | ||
692 | for (i = 0; i < *num_of_nodes; i++) { | ||
693 | char *temp; | ||
694 | int max_len; | ||
695 | struct dfs_info3_param *node = (*target_nodes)+i; | ||
696 | |||
697 | node->flags = le32_to_cpu(rsp->DFSFlags); | ||
698 | if (is_unicode) { | ||
699 | __le16 *tmp = kmalloc(strlen(searchName)*2 + 2, | ||
700 | GFP_KERNEL); | ||
701 | if (tmp == NULL) { | ||
702 | rc = -ENOMEM; | ||
703 | goto parse_DFS_referrals_exit; | ||
704 | } | ||
705 | cifsConvertToUTF16((__le16 *) tmp, searchName, | ||
706 | PATH_MAX, nls_codepage, remap); | ||
707 | node->path_consumed = cifs_utf16_bytes(tmp, | ||
708 | le16_to_cpu(rsp->PathConsumed), | ||
709 | nls_codepage); | ||
710 | kfree(tmp); | ||
711 | } else | ||
712 | node->path_consumed = le16_to_cpu(rsp->PathConsumed); | ||
713 | |||
714 | node->server_type = le16_to_cpu(ref->ServerType); | ||
715 | node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags); | ||
716 | |||
717 | /* copy DfsPath */ | ||
718 | temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset); | ||
719 | max_len = data_end - temp; | ||
720 | node->path_name = cifs_strndup_from_utf16(temp, max_len, | ||
721 | is_unicode, nls_codepage); | ||
722 | if (!node->path_name) { | ||
723 | rc = -ENOMEM; | ||
724 | goto parse_DFS_referrals_exit; | ||
725 | } | ||
726 | |||
727 | /* copy link target UNC */ | ||
728 | temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset); | ||
729 | max_len = data_end - temp; | ||
730 | node->node_name = cifs_strndup_from_utf16(temp, max_len, | ||
731 | is_unicode, nls_codepage); | ||
732 | if (!node->node_name) { | ||
733 | rc = -ENOMEM; | ||
734 | goto parse_DFS_referrals_exit; | ||
735 | } | ||
736 | |||
737 | ref++; | ||
738 | } | ||
739 | |||
740 | parse_DFS_referrals_exit: | ||
741 | if (rc) { | ||
742 | free_dfs_info_array(*target_nodes, *num_of_nodes); | ||
743 | *target_nodes = NULL; | ||
744 | *num_of_nodes = 0; | ||
745 | } | ||
746 | return rc; | ||
747 | } | ||
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index dcbcc927399a..8b0502cd39af 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
@@ -498,7 +498,7 @@ setup_ntlmv2_ret: | |||
498 | } | 498 | } |
499 | 499 | ||
500 | enum securityEnum | 500 | enum securityEnum |
501 | select_sectype(struct TCP_Server_Info *server, enum securityEnum requested) | 501 | cifs_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested) |
502 | { | 502 | { |
503 | switch (server->negflavor) { | 503 | switch (server->negflavor) { |
504 | case CIFS_NEGFLAVOR_EXTENDED: | 504 | case CIFS_NEGFLAVOR_EXTENDED: |
@@ -1391,7 +1391,7 @@ static int select_sec(struct cifs_ses *ses, struct sess_data *sess_data) | |||
1391 | { | 1391 | { |
1392 | int type; | 1392 | int type; |
1393 | 1393 | ||
1394 | type = select_sectype(ses->server, ses->sectype); | 1394 | type = cifs_select_sectype(ses->server, ses->sectype); |
1395 | cifs_dbg(FYI, "sess setup type %d\n", type); | 1395 | cifs_dbg(FYI, "sess setup type %d\n", type); |
1396 | if (type == Unspecified) { | 1396 | if (type == Unspecified) { |
1397 | cifs_dbg(VFS, | 1397 | cifs_dbg(VFS, |
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index 67a987e4d026..cc93ba4da9b5 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c | |||
@@ -1087,6 +1087,7 @@ struct smb_version_operations smb1_operations = { | |||
1087 | .is_read_op = cifs_is_read_op, | 1087 | .is_read_op = cifs_is_read_op, |
1088 | .wp_retry_size = cifs_wp_retry_size, | 1088 | .wp_retry_size = cifs_wp_retry_size, |
1089 | .dir_needs_close = cifs_dir_needs_close, | 1089 | .dir_needs_close = cifs_dir_needs_close, |
1090 | .select_sectype = cifs_select_sectype, | ||
1090 | #ifdef CONFIG_CIFS_XATTR | 1091 | #ifdef CONFIG_CIFS_XATTR |
1091 | .query_all_EAs = CIFSSMBQAllEAs, | 1092 | .query_all_EAs = CIFSSMBQAllEAs, |
1092 | .set_EA = CIFSSMBSetEA, | 1093 | .set_EA = CIFSSMBSetEA, |
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c index b2aff0c6f22c..b4b1f0305f29 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, | |||
73 | nr_ioctl_req.Timeout = 0; /* use server default (120 seconds) */ | 73 | nr_ioctl_req.Timeout = 0; /* use server default (120 seconds) */ |
74 | nr_ioctl_req.Reserved = 0; | 74 | nr_ioctl_req.Reserved = 0; |
75 | rc = SMB2_ioctl(xid, oparms->tcon, fid->persistent_fid, | 75 | rc = SMB2_ioctl(xid, oparms->tcon, fid->persistent_fid, |
76 | fid->volatile_fid, FSCTL_LMR_REQUEST_RESILIENCY, true, | 76 | fid->volatile_fid, FSCTL_LMR_REQUEST_RESILIENCY, |
77 | true /* is_fsctl */, false /* use_ipc */, | ||
77 | (char *)&nr_ioctl_req, sizeof(nr_ioctl_req), | 78 | (char *)&nr_ioctl_req, sizeof(nr_ioctl_req), |
78 | NULL, NULL /* no return info */); | 79 | NULL, NULL /* no return info */); |
79 | if (rc == -EOPNOTSUPP) { | 80 | if (rc == -EOPNOTSUPP) { |
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index a44b4dbe4aae..0231108d9387 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) | |||
282 | 282 | ||
283 | rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, | 283 | rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, |
284 | FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */, | 284 | FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */, |
285 | false /* use_ipc */, | ||
285 | NULL /* no data input */, 0 /* no data input */, | 286 | NULL /* no data input */, 0 /* no data input */, |
286 | (char **)&out_buf, &ret_data_len); | 287 | (char **)&out_buf, &ret_data_len); |
287 | if (rc != 0) | 288 | if (rc != 0) |
@@ -571,6 +572,7 @@ SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon, | |||
571 | 572 | ||
572 | rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid, | 573 | rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid, |
573 | FSCTL_SRV_REQUEST_RESUME_KEY, true /* is_fsctl */, | 574 | FSCTL_SRV_REQUEST_RESUME_KEY, true /* is_fsctl */, |
575 | false /* use_ipc */, | ||
574 | NULL, 0 /* no input */, | 576 | NULL, 0 /* no input */, |
575 | (char **)&res_key, &ret_data_len); | 577 | (char **)&res_key, &ret_data_len); |
576 | 578 | ||
@@ -635,7 +637,8 @@ smb2_clone_range(const unsigned int xid, | |||
635 | /* Request server copy to target from src identified by key */ | 637 | /* Request server copy to target from src identified by key */ |
636 | rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid, | 638 | rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid, |
637 | trgtfile->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE, | 639 | trgtfile->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE, |
638 | true /* is_fsctl */, (char *)pcchunk, | 640 | true /* is_fsctl */, false /* use_ipc */, |
641 | (char *)pcchunk, | ||
639 | sizeof(struct copychunk_ioctl), (char **)&retbuf, | 642 | sizeof(struct copychunk_ioctl), (char **)&retbuf, |
640 | &ret_data_len); | 643 | &ret_data_len); |
641 | if (rc == 0) { | 644 | if (rc == 0) { |
@@ -787,7 +790,8 @@ static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon, | |||
787 | 790 | ||
788 | rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, | 791 | rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, |
789 | cfile->fid.volatile_fid, FSCTL_SET_SPARSE, | 792 | cfile->fid.volatile_fid, FSCTL_SET_SPARSE, |
790 | true /* is_fctl */, &setsparse, 1, NULL, NULL); | 793 | true /* is_fctl */, false /* use_ipc */, |
794 | &setsparse, 1, NULL, NULL); | ||
791 | if (rc) { | 795 | if (rc) { |
792 | tcon->broken_sparse_sup = true; | 796 | tcon->broken_sparse_sup = true; |
793 | cifs_dbg(FYI, "set sparse rc = %d\n", rc); | 797 | cifs_dbg(FYI, "set sparse rc = %d\n", rc); |
@@ -857,7 +861,8 @@ smb2_duplicate_extents(const unsigned int xid, | |||
857 | rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid, | 861 | rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid, |
858 | trgtfile->fid.volatile_fid, | 862 | trgtfile->fid.volatile_fid, |
859 | FSCTL_DUPLICATE_EXTENTS_TO_FILE, | 863 | FSCTL_DUPLICATE_EXTENTS_TO_FILE, |
860 | true /* is_fsctl */, (char *)&dup_ext_buf, | 864 | true /* is_fsctl */, false /* use_ipc */, |
865 | (char *)&dup_ext_buf, | ||
861 | sizeof(struct duplicate_extents_to_file), | 866 | sizeof(struct duplicate_extents_to_file), |
862 | NULL, | 867 | NULL, |
863 | &ret_data_len); | 868 | &ret_data_len); |
@@ -891,7 +896,8 @@ smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon, | |||
891 | return SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, | 896 | return SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, |
892 | cfile->fid.volatile_fid, | 897 | cfile->fid.volatile_fid, |
893 | FSCTL_SET_INTEGRITY_INFORMATION, | 898 | FSCTL_SET_INTEGRITY_INFORMATION, |
894 | true /* is_fsctl */, (char *)&integr_info, | 899 | true /* is_fsctl */, false /* use_ipc */, |
900 | (char *)&integr_info, | ||
895 | sizeof(struct fsctl_set_integrity_information_req), | 901 | sizeof(struct fsctl_set_integrity_information_req), |
896 | NULL, | 902 | NULL, |
897 | &ret_data_len); | 903 | &ret_data_len); |
@@ -910,7 +916,8 @@ smb3_enum_snapshots(const unsigned int xid, struct cifs_tcon *tcon, | |||
910 | rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, | 916 | rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, |
911 | cfile->fid.volatile_fid, | 917 | cfile->fid.volatile_fid, |
912 | FSCTL_SRV_ENUMERATE_SNAPSHOTS, | 918 | FSCTL_SRV_ENUMERATE_SNAPSHOTS, |
913 | true /* is_fsctl */, NULL, 0 /* no input data */, | 919 | true /* is_fsctl */, false /* use_ipc */, |
920 | NULL, 0 /* no input data */, | ||
914 | (char **)&retbuf, | 921 | (char **)&retbuf, |
915 | &ret_data_len); | 922 | &ret_data_len); |
916 | cifs_dbg(FYI, "enum snaphots ioctl returned %d and ret buflen is %d\n", | 923 | cifs_dbg(FYI, "enum snaphots ioctl returned %d and ret buflen is %d\n", |
@@ -1097,6 +1104,103 @@ smb2_new_lease_key(struct cifs_fid *fid) | |||
1097 | generate_random_uuid(fid->lease_key); | 1104 | generate_random_uuid(fid->lease_key); |
1098 | } | 1105 | } |
1099 | 1106 | ||
1107 | static int | ||
1108 | smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses, | ||
1109 | const char *search_name, | ||
1110 | struct dfs_info3_param **target_nodes, | ||
1111 | unsigned int *num_of_nodes, | ||
1112 | const struct nls_table *nls_codepage, int remap) | ||
1113 | { | ||
1114 | int rc; | ||
1115 | __le16 *utf16_path = NULL; | ||
1116 | int utf16_path_len = 0; | ||
1117 | struct cifs_tcon *tcon; | ||
1118 | struct fsctl_get_dfs_referral_req *dfs_req = NULL; | ||
1119 | struct get_dfs_referral_rsp *dfs_rsp = NULL; | ||
1120 | u32 dfs_req_size = 0, dfs_rsp_size = 0; | ||
1121 | |||
1122 | cifs_dbg(FYI, "smb2_get_dfs_refer path <%s>\n", search_name); | ||
1123 | |||
1124 | /* | ||
1125 | * Use any tcon from the current session. Here, the first one. | ||
1126 | */ | ||
1127 | spin_lock(&cifs_tcp_ses_lock); | ||
1128 | tcon = list_first_entry_or_null(&ses->tcon_list, struct cifs_tcon, | ||
1129 | tcon_list); | ||
1130 | if (tcon) | ||
1131 | tcon->tc_count++; | ||
1132 | spin_unlock(&cifs_tcp_ses_lock); | ||
1133 | |||
1134 | if (!tcon) { | ||
1135 | cifs_dbg(VFS, "session %p has no tcon available for a dfs referral request\n", | ||
1136 | ses); | ||
1137 | rc = -ENOTCONN; | ||
1138 | goto out; | ||
1139 | } | ||
1140 | |||
1141 | utf16_path = cifs_strndup_to_utf16(search_name, PATH_MAX, | ||
1142 | &utf16_path_len, | ||
1143 | nls_codepage, remap); | ||
1144 | if (!utf16_path) { | ||
1145 | rc = -ENOMEM; | ||
1146 | goto out; | ||
1147 | } | ||
1148 | |||
1149 | dfs_req_size = sizeof(*dfs_req) + utf16_path_len; | ||
1150 | dfs_req = kzalloc(dfs_req_size, GFP_KERNEL); | ||
1151 | if (!dfs_req) { | ||
1152 | rc = -ENOMEM; | ||
1153 | goto out; | ||
1154 | } | ||
1155 | |||
1156 | /* Highest DFS referral version understood */ | ||
1157 | dfs_req->MaxReferralLevel = DFS_VERSION; | ||
1158 | |||
1159 | /* Path to resolve in an UTF-16 null-terminated string */ | ||
1160 | memcpy(dfs_req->RequestFileName, utf16_path, utf16_path_len); | ||
1161 | |||
1162 | do { | ||
1163 | /* try first with IPC */ | ||
1164 | rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, | ||
1165 | FSCTL_DFS_GET_REFERRALS, | ||
1166 | true /* is_fsctl */, true /* use_ipc */, | ||
1167 | (char *)dfs_req, dfs_req_size, | ||
1168 | (char **)&dfs_rsp, &dfs_rsp_size); | ||
1169 | if (rc == -ENOTCONN) { | ||
1170 | /* try with normal tcon */ | ||
1171 | rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, | ||
1172 | FSCTL_DFS_GET_REFERRALS, | ||
1173 | true /* is_fsctl */, false /*use_ipc*/, | ||
1174 | (char *)dfs_req, dfs_req_size, | ||
1175 | (char **)&dfs_rsp, &dfs_rsp_size); | ||
1176 | } | ||
1177 | } while (rc == -EAGAIN); | ||
1178 | |||
1179 | if (rc) { | ||
1180 | cifs_dbg(VFS, "ioctl error in smb2_get_dfs_refer rc=%d\n", rc); | ||
1181 | goto out; | ||
1182 | } | ||
1183 | |||
1184 | rc = parse_dfs_referrals(dfs_rsp, dfs_rsp_size, | ||
1185 | num_of_nodes, target_nodes, | ||
1186 | nls_codepage, remap, search_name, | ||
1187 | true /* is_unicode */); | ||
1188 | if (rc) { | ||
1189 | cifs_dbg(VFS, "parse error in smb2_get_dfs_refer rc=%d\n", rc); | ||
1190 | goto out; | ||
1191 | } | ||
1192 | |||
1193 | out: | ||
1194 | if (tcon) { | ||
1195 | spin_lock(&cifs_tcp_ses_lock); | ||
1196 | tcon->tc_count--; | ||
1197 | spin_unlock(&cifs_tcp_ses_lock); | ||
1198 | } | ||
1199 | kfree(utf16_path); | ||
1200 | kfree(dfs_req); | ||
1201 | kfree(dfs_rsp); | ||
1202 | return rc; | ||
1203 | } | ||
1100 | #define SMB2_SYMLINK_STRUCT_SIZE \ | 1204 | #define SMB2_SYMLINK_STRUCT_SIZE \ |
1101 | (sizeof(struct smb2_err_rsp) - 1 + sizeof(struct smb2_symlink_err_rsp)) | 1205 | (sizeof(struct smb2_err_rsp) - 1 + sizeof(struct smb2_symlink_err_rsp)) |
1102 | 1206 | ||
@@ -1220,7 +1324,8 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon, | |||
1220 | 1324 | ||
1221 | rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, | 1325 | rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, |
1222 | cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA, | 1326 | cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA, |
1223 | true /* is_fctl */, (char *)&fsctl_buf, | 1327 | true /* is_fctl */, false /* use_ipc */, |
1328 | (char *)&fsctl_buf, | ||
1224 | sizeof(struct file_zero_data_information), NULL, NULL); | 1329 | sizeof(struct file_zero_data_information), NULL, NULL); |
1225 | free_xid(xid); | 1330 | free_xid(xid); |
1226 | return rc; | 1331 | return rc; |
@@ -1254,7 +1359,8 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon, | |||
1254 | 1359 | ||
1255 | rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, | 1360 | rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, |
1256 | cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA, | 1361 | cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA, |
1257 | true /* is_fctl */, (char *)&fsctl_buf, | 1362 | true /* is_fctl */, false /* use_ipc */, |
1363 | (char *)&fsctl_buf, | ||
1258 | sizeof(struct file_zero_data_information), NULL, NULL); | 1364 | sizeof(struct file_zero_data_information), NULL, NULL); |
1259 | free_xid(xid); | 1365 | free_xid(xid); |
1260 | return rc; | 1366 | return rc; |
@@ -1609,6 +1715,26 @@ static void cifs_crypt_complete(struct crypto_async_request *req, int err) | |||
1609 | complete(&res->completion); | 1715 | complete(&res->completion); |
1610 | } | 1716 | } |
1611 | 1717 | ||
1718 | static int | ||
1719 | smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key) | ||
1720 | { | ||
1721 | struct cifs_ses *ses; | ||
1722 | u8 *ses_enc_key; | ||
1723 | |||
1724 | spin_lock(&cifs_tcp_ses_lock); | ||
1725 | list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { | ||
1726 | if (ses->Suid != ses_id) | ||
1727 | continue; | ||
1728 | ses_enc_key = enc ? ses->smb3encryptionkey : | ||
1729 | ses->smb3decryptionkey; | ||
1730 | memcpy(key, ses_enc_key, SMB3_SIGN_KEY_SIZE); | ||
1731 | spin_unlock(&cifs_tcp_ses_lock); | ||
1732 | return 0; | ||
1733 | } | ||
1734 | spin_unlock(&cifs_tcp_ses_lock); | ||
1735 | |||
1736 | return 1; | ||
1737 | } | ||
1612 | /* | 1738 | /* |
1613 | * Encrypt or decrypt @rqst message. @rqst has the following format: | 1739 | * Encrypt or decrypt @rqst message. @rqst has the following format: |
1614 | * iov[0] - transform header (associate data), | 1740 | * iov[0] - transform header (associate data), |
@@ -1622,10 +1748,10 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) | |||
1622 | struct smb2_transform_hdr *tr_hdr = | 1748 | struct smb2_transform_hdr *tr_hdr = |
1623 | (struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base; | 1749 | (struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base; |
1624 | unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24; | 1750 | unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24; |
1625 | struct cifs_ses *ses; | ||
1626 | int rc = 0; | 1751 | int rc = 0; |
1627 | struct scatterlist *sg; | 1752 | struct scatterlist *sg; |
1628 | u8 sign[SMB2_SIGNATURE_SIZE] = {}; | 1753 | u8 sign[SMB2_SIGNATURE_SIZE] = {}; |
1754 | u8 key[SMB3_SIGN_KEY_SIZE]; | ||
1629 | struct aead_request *req; | 1755 | struct aead_request *req; |
1630 | char *iv; | 1756 | char *iv; |
1631 | unsigned int iv_len; | 1757 | unsigned int iv_len; |
@@ -1635,9 +1761,10 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) | |||
1635 | 1761 | ||
1636 | init_completion(&result.completion); | 1762 | init_completion(&result.completion); |
1637 | 1763 | ||
1638 | ses = smb2_find_smb_ses(server, tr_hdr->SessionId); | 1764 | rc = smb2_get_enc_key(server, tr_hdr->SessionId, enc, key); |
1639 | if (!ses) { | 1765 | if (rc) { |
1640 | cifs_dbg(VFS, "%s: Could not find session\n", __func__); | 1766 | cifs_dbg(VFS, "%s: Could not get %scryption key\n", __func__, |
1767 | enc ? "en" : "de"); | ||
1641 | return 0; | 1768 | return 0; |
1642 | } | 1769 | } |
1643 | 1770 | ||
@@ -1649,8 +1776,7 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) | |||
1649 | 1776 | ||
1650 | tfm = enc ? server->secmech.ccmaesencrypt : | 1777 | tfm = enc ? server->secmech.ccmaesencrypt : |
1651 | server->secmech.ccmaesdecrypt; | 1778 | server->secmech.ccmaesdecrypt; |
1652 | rc = crypto_aead_setkey(tfm, enc ? ses->smb3encryptionkey : | 1779 | rc = crypto_aead_setkey(tfm, key, SMB3_SIGN_KEY_SIZE); |
1653 | ses->smb3decryptionkey, SMB3_SIGN_KEY_SIZE); | ||
1654 | if (rc) { | 1780 | if (rc) { |
1655 | cifs_dbg(VFS, "%s: Failed to set aead key %d\n", __func__, rc); | 1781 | cifs_dbg(VFS, "%s: Failed to set aead key %d\n", __func__, rc); |
1656 | return rc; | 1782 | return rc; |
@@ -2254,6 +2380,8 @@ struct smb_version_operations smb20_operations = { | |||
2254 | .clone_range = smb2_clone_range, | 2380 | .clone_range = smb2_clone_range, |
2255 | .wp_retry_size = smb2_wp_retry_size, | 2381 | .wp_retry_size = smb2_wp_retry_size, |
2256 | .dir_needs_close = smb2_dir_needs_close, | 2382 | .dir_needs_close = smb2_dir_needs_close, |
2383 | .get_dfs_refer = smb2_get_dfs_refer, | ||
2384 | .select_sectype = smb2_select_sectype, | ||
2257 | }; | 2385 | }; |
2258 | 2386 | ||
2259 | struct smb_version_operations smb21_operations = { | 2387 | struct smb_version_operations smb21_operations = { |
@@ -2335,6 +2463,8 @@ struct smb_version_operations smb21_operations = { | |||
2335 | .wp_retry_size = smb2_wp_retry_size, | 2463 | .wp_retry_size = smb2_wp_retry_size, |
2336 | .dir_needs_close = smb2_dir_needs_close, | 2464 | .dir_needs_close = smb2_dir_needs_close, |
2337 | .enum_snapshots = smb3_enum_snapshots, | 2465 | .enum_snapshots = smb3_enum_snapshots, |
2466 | .get_dfs_refer = smb2_get_dfs_refer, | ||
2467 | .select_sectype = smb2_select_sectype, | ||
2338 | }; | 2468 | }; |
2339 | 2469 | ||
2340 | struct smb_version_operations smb30_operations = { | 2470 | struct smb_version_operations smb30_operations = { |
@@ -2426,6 +2556,8 @@ struct smb_version_operations smb30_operations = { | |||
2426 | .free_transform_rq = smb3_free_transform_rq, | 2556 | .free_transform_rq = smb3_free_transform_rq, |
2427 | .is_transform_hdr = smb3_is_transform_hdr, | 2557 | .is_transform_hdr = smb3_is_transform_hdr, |
2428 | .receive_transform = smb3_receive_transform, | 2558 | .receive_transform = smb3_receive_transform, |
2559 | .get_dfs_refer = smb2_get_dfs_refer, | ||
2560 | .select_sectype = smb2_select_sectype, | ||
2429 | }; | 2561 | }; |
2430 | 2562 | ||
2431 | #ifdef CONFIG_CIFS_SMB311 | 2563 | #ifdef CONFIG_CIFS_SMB311 |
@@ -2518,6 +2650,8 @@ struct smb_version_operations smb311_operations = { | |||
2518 | .free_transform_rq = smb3_free_transform_rq, | 2650 | .free_transform_rq = smb3_free_transform_rq, |
2519 | .is_transform_hdr = smb3_is_transform_hdr, | 2651 | .is_transform_hdr = smb3_is_transform_hdr, |
2520 | .receive_transform = smb3_receive_transform, | 2652 | .receive_transform = smb3_receive_transform, |
2653 | .get_dfs_refer = smb2_get_dfs_refer, | ||
2654 | .select_sectype = smb2_select_sectype, | ||
2521 | }; | 2655 | }; |
2522 | #endif /* CIFS_SMB311 */ | 2656 | #endif /* CIFS_SMB311 */ |
2523 | 2657 | ||
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index ad83b3db2840..7446496850a3 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) | |||
620 | 620 | ||
621 | rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, | 621 | rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, |
622 | FSCTL_VALIDATE_NEGOTIATE_INFO, true /* is_fsctl */, | 622 | FSCTL_VALIDATE_NEGOTIATE_INFO, true /* is_fsctl */, |
623 | false /* use_ipc */, | ||
623 | (char *)&vneg_inbuf, sizeof(struct validate_negotiate_info_req), | 624 | (char *)&vneg_inbuf, sizeof(struct validate_negotiate_info_req), |
624 | (char **)&pneg_rsp, &rsplen); | 625 | (char **)&pneg_rsp, &rsplen); |
625 | 626 | ||
@@ -656,6 +657,28 @@ vneg_out: | |||
656 | return -EIO; | 657 | return -EIO; |
657 | } | 658 | } |
658 | 659 | ||
660 | enum securityEnum | ||
661 | smb2_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested) | ||
662 | { | ||
663 | switch (requested) { | ||
664 | case Kerberos: | ||
665 | case RawNTLMSSP: | ||
666 | return requested; | ||
667 | case NTLMv2: | ||
668 | return RawNTLMSSP; | ||
669 | case Unspecified: | ||
670 | if (server->sec_ntlmssp && | ||
671 | (global_secflags & CIFSSEC_MAY_NTLMSSP)) | ||
672 | return RawNTLMSSP; | ||
673 | if ((server->sec_kerberos || server->sec_mskerberos) && | ||
674 | (global_secflags & CIFSSEC_MAY_KRB5)) | ||
675 | return Kerberos; | ||
676 | /* Fallthrough */ | ||
677 | default: | ||
678 | return Unspecified; | ||
679 | } | ||
680 | } | ||
681 | |||
659 | struct SMB2_sess_data { | 682 | struct SMB2_sess_data { |
660 | unsigned int xid; | 683 | unsigned int xid; |
661 | struct cifs_ses *ses; | 684 | struct cifs_ses *ses; |
@@ -1008,10 +1031,17 @@ out: | |||
1008 | static int | 1031 | static int |
1009 | SMB2_select_sec(struct cifs_ses *ses, struct SMB2_sess_data *sess_data) | 1032 | SMB2_select_sec(struct cifs_ses *ses, struct SMB2_sess_data *sess_data) |
1010 | { | 1033 | { |
1011 | if (ses->sectype != Kerberos && ses->sectype != RawNTLMSSP) | 1034 | int type; |
1012 | ses->sectype = RawNTLMSSP; | 1035 | |
1036 | type = smb2_select_sectype(ses->server, ses->sectype); | ||
1037 | cifs_dbg(FYI, "sess setup type %d\n", type); | ||
1038 | if (type == Unspecified) { | ||
1039 | cifs_dbg(VFS, | ||
1040 | "Unable to select appropriate authentication method!"); | ||
1041 | return -EINVAL; | ||
1042 | } | ||
1013 | 1043 | ||
1014 | switch (ses->sectype) { | 1044 | switch (type) { |
1015 | case Kerberos: | 1045 | case Kerberos: |
1016 | sess_data->func = SMB2_auth_kerberos; | 1046 | sess_data->func = SMB2_auth_kerberos; |
1017 | break; | 1047 | break; |
@@ -1019,7 +1049,7 @@ SMB2_select_sec(struct cifs_ses *ses, struct SMB2_sess_data *sess_data) | |||
1019 | sess_data->func = SMB2_sess_auth_rawntlmssp_negotiate; | 1049 | sess_data->func = SMB2_sess_auth_rawntlmssp_negotiate; |
1020 | break; | 1050 | break; |
1021 | default: | 1051 | default: |
1022 | cifs_dbg(VFS, "secType %d not supported!\n", ses->sectype); | 1052 | cifs_dbg(VFS, "secType %d not supported!\n", type); |
1023 | return -EOPNOTSUPP; | 1053 | return -EOPNOTSUPP; |
1024 | } | 1054 | } |
1025 | 1055 | ||
@@ -1167,8 +1197,8 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, | |||
1167 | 1197 | ||
1168 | /* since no tcon, smb2_init can not do this, so do here */ | 1198 | /* since no tcon, smb2_init can not do this, so do here */ |
1169 | req->hdr.sync_hdr.SessionId = ses->Suid; | 1199 | req->hdr.sync_hdr.SessionId = ses->Suid; |
1170 | /* if (ses->server->sec_mode & SECMODE_SIGN_REQUIRED) | 1200 | if (ses->server->sign) |
1171 | req->hdr.Flags |= SMB2_FLAGS_SIGNED; */ | 1201 | req->hdr.sync_hdr.Flags |= SMB2_FLAGS_SIGNED; |
1172 | } else if (encryption_required(tcon)) | 1202 | } else if (encryption_required(tcon)) |
1173 | flags |= CIFS_TRANSFORM_REQ; | 1203 | flags |= CIFS_TRANSFORM_REQ; |
1174 | 1204 | ||
@@ -1527,6 +1557,51 @@ add_durable_context(struct kvec *iov, unsigned int *num_iovec, | |||
1527 | return 0; | 1557 | return 0; |
1528 | } | 1558 | } |
1529 | 1559 | ||
1560 | static int | ||
1561 | alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len, | ||
1562 | const char *treename, const __le16 *path) | ||
1563 | { | ||
1564 | int treename_len, path_len; | ||
1565 | struct nls_table *cp; | ||
1566 | const __le16 sep[] = {cpu_to_le16('\\'), cpu_to_le16(0x0000)}; | ||
1567 | |||
1568 | /* | ||
1569 | * skip leading "\\" | ||
1570 | */ | ||
1571 | treename_len = strlen(treename); | ||
1572 | if (treename_len < 2 || !(treename[0] == '\\' && treename[1] == '\\')) | ||
1573 | return -EINVAL; | ||
1574 | |||
1575 | treename += 2; | ||
1576 | treename_len -= 2; | ||
1577 | |||
1578 | path_len = UniStrnlen((wchar_t *)path, PATH_MAX); | ||
1579 | |||
1580 | /* | ||
1581 | * make room for one path separator between the treename and | ||
1582 | * path | ||
1583 | */ | ||
1584 | *out_len = treename_len + 1 + path_len; | ||
1585 | |||
1586 | /* | ||
1587 | * final path needs to be null-terminated UTF16 with a | ||
1588 | * size aligned to 8 | ||
1589 | */ | ||
1590 | |||
1591 | *out_size = roundup((*out_len+1)*2, 8); | ||
1592 | *out_path = kzalloc(*out_size, GFP_KERNEL); | ||
1593 | if (!*out_path) | ||
1594 | return -ENOMEM; | ||
1595 | |||
1596 | cp = load_nls_default(); | ||
1597 | cifs_strtoUTF16(*out_path, treename, treename_len, cp); | ||
1598 | UniStrcat(*out_path, sep); | ||
1599 | UniStrcat(*out_path, path); | ||
1600 | unload_nls(cp); | ||
1601 | |||
1602 | return 0; | ||
1603 | } | ||
1604 | |||
1530 | int | 1605 | int |
1531 | SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, | 1606 | SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, |
1532 | __u8 *oplock, struct smb2_file_all_info *buf, | 1607 | __u8 *oplock, struct smb2_file_all_info *buf, |
@@ -1575,30 +1650,49 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, | |||
1575 | req->ShareAccess = FILE_SHARE_ALL_LE; | 1650 | req->ShareAccess = FILE_SHARE_ALL_LE; |
1576 | req->CreateDisposition = cpu_to_le32(oparms->disposition); | 1651 | req->CreateDisposition = cpu_to_le32(oparms->disposition); |
1577 | req->CreateOptions = cpu_to_le32(oparms->create_options & CREATE_OPTIONS_MASK); | 1652 | req->CreateOptions = cpu_to_le32(oparms->create_options & CREATE_OPTIONS_MASK); |
1578 | uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2; | ||
1579 | /* do not count rfc1001 len field */ | ||
1580 | req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req) - 4); | ||
1581 | 1653 | ||
1582 | iov[0].iov_base = (char *)req; | 1654 | iov[0].iov_base = (char *)req; |
1583 | /* 4 for rfc1002 length field */ | 1655 | /* 4 for rfc1002 length field */ |
1584 | iov[0].iov_len = get_rfc1002_length(req) + 4; | 1656 | iov[0].iov_len = get_rfc1002_length(req) + 4; |
1585 | |||
1586 | /* MUST set path len (NameLength) to 0 opening root of share */ | ||
1587 | req->NameLength = cpu_to_le16(uni_path_len - 2); | ||
1588 | /* -1 since last byte is buf[0] which is sent below (path) */ | 1657 | /* -1 since last byte is buf[0] which is sent below (path) */ |
1589 | iov[0].iov_len--; | 1658 | iov[0].iov_len--; |
1590 | if (uni_path_len % 8 != 0) { | 1659 | |
1591 | copy_size = uni_path_len / 8 * 8; | 1660 | req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req) - 4); |
1592 | if (copy_size < uni_path_len) | 1661 | |
1593 | copy_size += 8; | 1662 | /* [MS-SMB2] 2.2.13 NameOffset: |
1594 | 1663 | * If SMB2_FLAGS_DFS_OPERATIONS is set in the Flags field of | |
1595 | copy_path = kzalloc(copy_size, GFP_KERNEL); | 1664 | * the SMB2 header, the file name includes a prefix that will |
1596 | if (!copy_path) | 1665 | * be processed during DFS name normalization as specified in |
1597 | return -ENOMEM; | 1666 | * section 3.3.5.9. Otherwise, the file name is relative to |
1598 | memcpy((char *)copy_path, (const char *)path, | 1667 | * the share that is identified by the TreeId in the SMB2 |
1599 | uni_path_len); | 1668 | * header. |
1669 | */ | ||
1670 | if (tcon->share_flags & SHI1005_FLAGS_DFS) { | ||
1671 | int name_len; | ||
1672 | |||
1673 | req->hdr.sync_hdr.Flags |= SMB2_FLAGS_DFS_OPERATIONS; | ||
1674 | rc = alloc_path_with_tree_prefix(©_path, ©_size, | ||
1675 | &name_len, | ||
1676 | tcon->treeName, path); | ||
1677 | if (rc) | ||
1678 | return rc; | ||
1679 | req->NameLength = cpu_to_le16(name_len * 2); | ||
1600 | uni_path_len = copy_size; | 1680 | uni_path_len = copy_size; |
1601 | path = copy_path; | 1681 | path = copy_path; |
1682 | } else { | ||
1683 | uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2; | ||
1684 | /* MUST set path len (NameLength) to 0 opening root of share */ | ||
1685 | req->NameLength = cpu_to_le16(uni_path_len - 2); | ||
1686 | if (uni_path_len % 8 != 0) { | ||
1687 | copy_size = roundup(uni_path_len, 8); | ||
1688 | copy_path = kzalloc(copy_size, GFP_KERNEL); | ||
1689 | if (!copy_path) | ||
1690 | return -ENOMEM; | ||
1691 | memcpy((char *)copy_path, (const char *)path, | ||
1692 | uni_path_len); | ||
1693 | uni_path_len = copy_size; | ||
1694 | path = copy_path; | ||
1695 | } | ||
1602 | } | 1696 | } |
1603 | 1697 | ||
1604 | iov[1].iov_len = uni_path_len; | 1698 | iov[1].iov_len = uni_path_len; |
@@ -1683,8 +1777,9 @@ creat_exit: | |||
1683 | */ | 1777 | */ |
1684 | int | 1778 | int |
1685 | SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, | 1779 | SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, |
1686 | u64 volatile_fid, u32 opcode, bool is_fsctl, char *in_data, | 1780 | u64 volatile_fid, u32 opcode, bool is_fsctl, bool use_ipc, |
1687 | u32 indatalen, char **out_data, u32 *plen /* returned data len */) | 1781 | char *in_data, u32 indatalen, |
1782 | char **out_data, u32 *plen /* returned data len */) | ||
1688 | { | 1783 | { |
1689 | struct smb2_ioctl_req *req; | 1784 | struct smb2_ioctl_req *req; |
1690 | struct smb2_ioctl_rsp *rsp; | 1785 | struct smb2_ioctl_rsp *rsp; |
@@ -1721,6 +1816,16 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, | |||
1721 | if (rc) | 1816 | if (rc) |
1722 | return rc; | 1817 | return rc; |
1723 | 1818 | ||
1819 | if (use_ipc) { | ||
1820 | if (ses->ipc_tid == 0) { | ||
1821 | cifs_small_buf_release(req); | ||
1822 | return -ENOTCONN; | ||
1823 | } | ||
1824 | |||
1825 | cifs_dbg(FYI, "replacing tid 0x%x with IPC tid 0x%x\n", | ||
1826 | req->hdr.sync_hdr.TreeId, ses->ipc_tid); | ||
1827 | req->hdr.sync_hdr.TreeId = ses->ipc_tid; | ||
1828 | } | ||
1724 | if (encryption_required(tcon)) | 1829 | if (encryption_required(tcon)) |
1725 | flags |= CIFS_TRANSFORM_REQ; | 1830 | flags |= CIFS_TRANSFORM_REQ; |
1726 | 1831 | ||
@@ -1843,6 +1948,7 @@ SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon, | |||
1843 | 1948 | ||
1844 | rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid, | 1949 | rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid, |
1845 | FSCTL_SET_COMPRESSION, true /* is_fsctl */, | 1950 | FSCTL_SET_COMPRESSION, true /* is_fsctl */, |
1951 | false /* use_ipc */, | ||
1846 | (char *)&fsctl_input /* data input */, | 1952 | (char *)&fsctl_input /* data input */, |
1847 | 2 /* in data len */, &ret_data /* out data */, NULL); | 1953 | 2 /* in data len */, &ret_data /* out data */, NULL); |
1848 | 1954 | ||
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index c03b252501a1..18700fd25a0b 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h | |||
@@ -695,6 +695,14 @@ struct fsctl_get_integrity_information_rsp { | |||
695 | /* Integrity flags for above */ | 695 | /* Integrity flags for above */ |
696 | #define FSCTL_INTEGRITY_FLAG_CHECKSUM_ENFORCEMENT_OFF 0x00000001 | 696 | #define FSCTL_INTEGRITY_FLAG_CHECKSUM_ENFORCEMENT_OFF 0x00000001 |
697 | 697 | ||
698 | /* See MS-DFSC 2.2.2 */ | ||
699 | struct fsctl_get_dfs_referral_req { | ||
700 | __le16 MaxReferralLevel; | ||
701 | __u8 RequestFileName[]; | ||
702 | } __packed; | ||
703 | |||
704 | /* DFS response is struct get_dfs_refer_rsp */ | ||
705 | |||
698 | /* See MS-SMB2 2.2.31.3 */ | 706 | /* See MS-SMB2 2.2.31.3 */ |
699 | struct network_resiliency_req { | 707 | struct network_resiliency_req { |
700 | __le32 Timeout; | 708 | __le32 Timeout; |
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 85fc7a789334..69e35873b1de 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, | |||
121 | struct smb2_err_rsp **err_buf); | 121 | struct smb2_err_rsp **err_buf); |
122 | extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, | 122 | extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, |
123 | u64 persistent_fid, u64 volatile_fid, u32 opcode, | 123 | u64 persistent_fid, u64 volatile_fid, u32 opcode, |
124 | bool is_fsctl, char *in_data, u32 indatalen, | 124 | bool is_fsctl, bool use_ipc, |
125 | char *in_data, u32 indatalen, | ||
125 | char **out_data, u32 *plen /* returned data len */); | 126 | char **out_data, u32 *plen /* returned data len */); |
126 | extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, | 127 | extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, |
127 | u64 persistent_file_id, u64 volatile_file_id); | 128 | u64 persistent_file_id, u64 volatile_file_id); |
@@ -180,4 +181,6 @@ extern int SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon, | |||
180 | __u8 *lease_key, const __le32 lease_state); | 181 | __u8 *lease_key, const __le32 lease_state); |
181 | extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *); | 182 | extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *); |
182 | 183 | ||
184 | extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *, | ||
185 | enum securityEnum); | ||
183 | #endif /* _SMB2PROTO_H */ | 186 | #endif /* _SMB2PROTO_H */ |