Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+446 -167
+3 -1
fs/cifs/cifs_dfs_ref.c
··· 303 303 * gives us the latter, so we must adjust the result. 304 304 */ 305 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 309 if (full_path == NULL) 308 310 goto cdda_exit; 309 311
+3 -3
fs/cifs/cifs_unicode.h
··· 130 130 * Returns: 131 131 * Address of the first string 132 132 */ 133 - static inline wchar_t * 134 - UniStrcat(wchar_t *ucs1, const wchar_t *ucs2) 133 + static inline __le16 * 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 138 while (*ucs1++) ; /* To end of first string */ 139 139 ucs1--; /* Return to the null */
+4 -1
fs/cifs/cifsglob.h
··· 443 443 int (*is_transform_hdr)(void *buf); 444 444 int (*receive_transform)(struct TCP_Server_Info *, 445 445 struct mid_q_entry **); 446 + enum securityEnum (*select_sectype)(struct TCP_Server_Info *, 447 + enum securityEnum); 448 + 446 449 }; 447 450 448 451 struct smb_version_values { ··· 825 822 int ses_count; /* reference counter */ 826 823 enum statusEnum status; 827 824 unsigned overrideSecFlg; /* if non-zero override global sec flags */ 828 - __u16 ipc_tid; /* special tid for connection to IPC share */ 825 + __u32 ipc_tid; /* special tid for connection to IPC share */ 829 826 char *serverOS; /* name of operating system underlying server */ 830 827 char *serverNOS; /* name of network operating system of server */ 831 828 char *serverDomain; /* security realm of server */
+10 -6
fs/cifs/cifspdu.h
··· 2086 2086 __u8 ServiceSiteGuid[16]; /* MBZ, ignored */ 2087 2087 } __attribute__((packed)) REFERRAL3; 2088 2088 2089 - typedef struct smb_com_transaction_get_dfs_refer_rsp { 2090 - struct smb_hdr hdr; /* wct = 10 */ 2091 - struct trans2_resp t2; 2092 - __u16 ByteCount; 2093 - __u8 Pad; 2089 + struct get_dfs_referral_rsp { 2094 2090 __le16 PathConsumed; 2095 2091 __le16 NumberOfReferrals; 2096 2092 __le32 DFSFlags; 2097 2093 REFERRAL3 referrals[1]; /* array of level 3 dfs_referral structures */ 2098 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 2105 /* DFS Flags */ 2102 2106 #define DFSREF_REFERRAL_SERVER 0x00000001 /* all targets are DFS roots */
+9
fs/cifs/cifsproto.h
··· 61 61 extern int init_cifs_spnego(void); 62 62 extern void exit_cifs_spnego(void); 63 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 66 extern char *cifs_build_path_to_root(struct smb_vol *vol, 65 67 struct cifs_sb_info *cifs_sb, 66 68 struct cifs_tcon *tcon, ··· 286 284 const struct nls_table *nls_codepage, 287 285 unsigned int *num_referrals, 288 286 struct dfs_info3_param **referrals, int remap); 287 + extern int parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, 288 + unsigned int *num_of_nodes, 289 + struct dfs_info3_param **target_nodes, 290 + const struct nls_table *nls_codepage, int remap, 291 + const char *searchName, bool is_unicode); 289 292 extern void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon, 290 293 struct cifs_sb_info *cifs_sb, 291 294 struct smb_vol *vol); ··· 533 526 int __cifs_calc_signature(struct smb_rqst *rqst, 534 527 struct TCP_Server_Info *server, char *signature, 535 528 struct shash_desc *shash); 529 + enum securityEnum cifs_select_sectype(struct TCP_Server_Info *, 530 + enum securityEnum); 536 531 #endif /* _CIFSPROTO_H */
+5 -114
fs/cifs/cifssmb.c
··· 4786 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 4789 int 4901 4790 CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses, 4902 4791 const char *search_name, struct dfs_info3_param **target_nodes, ··· 4882 4993 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset)); 4883 4994 4884 4995 /* parse returned result into more usable form */ 4885 - rc = parse_DFS_referrals(pSMBr, num_of_nodes, 4886 - target_nodes, nls_codepage, remap, 4887 - search_name); 4996 + rc = parse_dfs_referrals(&pSMBr->dfs_data, 4997 + le16_to_cpu(pSMBr->t2.DataCount), 4998 + num_of_nodes, target_nodes, nls_codepage, 4999 + remap, search_name, 5000 + (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0); 4888 5001 4889 5002 GetDFSRefExit: 4890 5003 cifs_buf_release(pSMB);
+2 -1
fs/cifs/connect.c
··· 2074 2074 * that was specified, or "Unspecified" if that sectype was not 2075 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 2079 return false; 2079 2080 2080 2081 /*
+12 -1
fs/cifs/dir.c
··· 81 81 char * 82 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 95 struct dentry *temp; 85 96 int namelen; 86 97 int dfsplen; ··· 103 92 unsigned seq; 104 93 105 94 dirsep = CIFS_DIR_SEP(cifs_sb); 106 - if (tcon->Flags & SMB_SHARE_IS_IN_DFS) 95 + if (prefix) 107 96 dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1); 108 97 else 109 98 dfsplen = 0;
+105
fs/cifs/misc.c
··· 640 640 cifs_add_pending_open_locked(fid, tlink, open); 641 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 + }
+2 -2
fs/cifs/sess.c
··· 498 498 } 499 499 500 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 503 switch (server->negflavor) { 504 504 case CIFS_NEGFLAVOR_EXTENDED: ··· 1391 1391 { 1392 1392 int type; 1393 1393 1394 - type = select_sectype(ses->server, ses->sectype); 1394 + type = cifs_select_sectype(ses->server, ses->sectype); 1395 1395 cifs_dbg(FYI, "sess setup type %d\n", type); 1396 1396 if (type == Unspecified) { 1397 1397 cifs_dbg(VFS,
+1
fs/cifs/smb1ops.c
··· 1087 1087 .is_read_op = cifs_is_read_op, 1088 1088 .wp_retry_size = cifs_wp_retry_size, 1089 1089 .dir_needs_close = cifs_dir_needs_close, 1090 + .select_sectype = cifs_select_sectype, 1090 1091 #ifdef CONFIG_CIFS_XATTR 1091 1092 .query_all_EAs = CIFSSMBQAllEAs, 1092 1093 .set_EA = CIFSSMBSetEA,
+2 -1
fs/cifs/smb2file.c
··· 73 73 nr_ioctl_req.Timeout = 0; /* use server default (120 seconds) */ 74 74 nr_ioctl_req.Reserved = 0; 75 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 78 (char *)&nr_ioctl_req, sizeof(nr_ioctl_req), 78 79 NULL, NULL /* no return info */); 79 80 if (rc == -EOPNOTSUPP) {
+147 -13
fs/cifs/smb2ops.c
··· 282 282 283 283 rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, 284 284 FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */, 285 + false /* use_ipc */, 285 286 NULL /* no data input */, 0 /* no data input */, 286 287 (char **)&out_buf, &ret_data_len); 287 288 if (rc != 0) ··· 572 571 573 572 rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid, 574 573 FSCTL_SRV_REQUEST_RESUME_KEY, true /* is_fsctl */, 574 + false /* use_ipc */, 575 575 NULL, 0 /* no input */, 576 576 (char **)&res_key, &ret_data_len); 577 577 ··· 637 635 /* Request server copy to target from src identified by key */ 638 636 rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid, 639 637 trgtfile->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE, 640 - true /* is_fsctl */, (char *)pcchunk, 638 + true /* is_fsctl */, false /* use_ipc */, 639 + (char *)pcchunk, 641 640 sizeof(struct copychunk_ioctl), (char **)&retbuf, 642 641 &ret_data_len); 643 642 if (rc == 0) { ··· 790 787 791 788 rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, 792 789 cfile->fid.volatile_fid, FSCTL_SET_SPARSE, 793 - true /* is_fctl */, &setsparse, 1, NULL, NULL); 790 + true /* is_fctl */, false /* use_ipc */, 791 + &setsparse, 1, NULL, NULL); 794 792 if (rc) { 795 793 tcon->broken_sparse_sup = true; 796 794 cifs_dbg(FYI, "set sparse rc = %d\n", rc); ··· 861 857 rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid, 862 858 trgtfile->fid.volatile_fid, 863 859 FSCTL_DUPLICATE_EXTENTS_TO_FILE, 864 - true /* is_fsctl */, (char *)&dup_ext_buf, 860 + true /* is_fsctl */, false /* use_ipc */, 861 + (char *)&dup_ext_buf, 865 862 sizeof(struct duplicate_extents_to_file), 866 863 NULL, 867 864 &ret_data_len); ··· 896 891 return SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, 897 892 cfile->fid.volatile_fid, 898 893 FSCTL_SET_INTEGRITY_INFORMATION, 899 - true /* is_fsctl */, (char *)&integr_info, 894 + true /* is_fsctl */, false /* use_ipc */, 895 + (char *)&integr_info, 900 896 sizeof(struct fsctl_set_integrity_information_req), 901 897 NULL, 902 898 &ret_data_len); ··· 916 910 rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, 917 911 cfile->fid.volatile_fid, 918 912 FSCTL_SRV_ENUMERATE_SNAPSHOTS, 919 - true /* is_fsctl */, NULL, 0 /* no input data */, 913 + true /* is_fsctl */, false /* use_ipc */, 914 + NULL, 0 /* no input data */, 920 915 (char **)&retbuf, 921 916 &ret_data_len); 922 917 cifs_dbg(FYI, "enum snaphots ioctl returned %d and ret buflen is %d\n", ··· 1104 1097 generate_random_uuid(fid->lease_key); 1105 1098 } 1106 1099 1100 + static int 1101 + smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses, 1102 + const char *search_name, 1103 + struct dfs_info3_param **target_nodes, 1104 + unsigned int *num_of_nodes, 1105 + const struct nls_table *nls_codepage, int remap) 1106 + { 1107 + int rc; 1108 + __le16 *utf16_path = NULL; 1109 + int utf16_path_len = 0; 1110 + struct cifs_tcon *tcon; 1111 + struct fsctl_get_dfs_referral_req *dfs_req = NULL; 1112 + struct get_dfs_referral_rsp *dfs_rsp = NULL; 1113 + u32 dfs_req_size = 0, dfs_rsp_size = 0; 1114 + 1115 + cifs_dbg(FYI, "smb2_get_dfs_refer path <%s>\n", search_name); 1116 + 1117 + /* 1118 + * Use any tcon from the current session. Here, the first one. 1119 + */ 1120 + spin_lock(&cifs_tcp_ses_lock); 1121 + tcon = list_first_entry_or_null(&ses->tcon_list, struct cifs_tcon, 1122 + tcon_list); 1123 + if (tcon) 1124 + tcon->tc_count++; 1125 + spin_unlock(&cifs_tcp_ses_lock); 1126 + 1127 + if (!tcon) { 1128 + cifs_dbg(VFS, "session %p has no tcon available for a dfs referral request\n", 1129 + ses); 1130 + rc = -ENOTCONN; 1131 + goto out; 1132 + } 1133 + 1134 + utf16_path = cifs_strndup_to_utf16(search_name, PATH_MAX, 1135 + &utf16_path_len, 1136 + nls_codepage, remap); 1137 + if (!utf16_path) { 1138 + rc = -ENOMEM; 1139 + goto out; 1140 + } 1141 + 1142 + dfs_req_size = sizeof(*dfs_req) + utf16_path_len; 1143 + dfs_req = kzalloc(dfs_req_size, GFP_KERNEL); 1144 + if (!dfs_req) { 1145 + rc = -ENOMEM; 1146 + goto out; 1147 + } 1148 + 1149 + /* Highest DFS referral version understood */ 1150 + dfs_req->MaxReferralLevel = DFS_VERSION; 1151 + 1152 + /* Path to resolve in an UTF-16 null-terminated string */ 1153 + memcpy(dfs_req->RequestFileName, utf16_path, utf16_path_len); 1154 + 1155 + do { 1156 + /* try first with IPC */ 1157 + rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, 1158 + FSCTL_DFS_GET_REFERRALS, 1159 + true /* is_fsctl */, true /* use_ipc */, 1160 + (char *)dfs_req, dfs_req_size, 1161 + (char **)&dfs_rsp, &dfs_rsp_size); 1162 + if (rc == -ENOTCONN) { 1163 + /* try with normal tcon */ 1164 + rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, 1165 + FSCTL_DFS_GET_REFERRALS, 1166 + true /* is_fsctl */, false /*use_ipc*/, 1167 + (char *)dfs_req, dfs_req_size, 1168 + (char **)&dfs_rsp, &dfs_rsp_size); 1169 + } 1170 + } while (rc == -EAGAIN); 1171 + 1172 + if (rc) { 1173 + cifs_dbg(VFS, "ioctl error in smb2_get_dfs_refer rc=%d\n", rc); 1174 + goto out; 1175 + } 1176 + 1177 + rc = parse_dfs_referrals(dfs_rsp, dfs_rsp_size, 1178 + num_of_nodes, target_nodes, 1179 + nls_codepage, remap, search_name, 1180 + true /* is_unicode */); 1181 + if (rc) { 1182 + cifs_dbg(VFS, "parse error in smb2_get_dfs_refer rc=%d\n", rc); 1183 + goto out; 1184 + } 1185 + 1186 + out: 1187 + if (tcon) { 1188 + spin_lock(&cifs_tcp_ses_lock); 1189 + tcon->tc_count--; 1190 + spin_unlock(&cifs_tcp_ses_lock); 1191 + } 1192 + kfree(utf16_path); 1193 + kfree(dfs_req); 1194 + kfree(dfs_rsp); 1195 + return rc; 1196 + } 1107 1197 #define SMB2_SYMLINK_STRUCT_SIZE \ 1108 1198 (sizeof(struct smb2_err_rsp) - 1 + sizeof(struct smb2_symlink_err_rsp)) 1109 1199 ··· 1324 1220 1325 1221 rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, 1326 1222 cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA, 1327 - true /* is_fctl */, (char *)&fsctl_buf, 1223 + true /* is_fctl */, false /* use_ipc */, 1224 + (char *)&fsctl_buf, 1328 1225 sizeof(struct file_zero_data_information), NULL, NULL); 1329 1226 free_xid(xid); 1330 1227 return rc; ··· 1359 1254 1360 1255 rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, 1361 1256 cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA, 1362 - true /* is_fctl */, (char *)&fsctl_buf, 1257 + true /* is_fctl */, false /* use_ipc */, 1258 + (char *)&fsctl_buf, 1363 1259 sizeof(struct file_zero_data_information), NULL, NULL); 1364 1260 free_xid(xid); 1365 1261 return rc; ··· 1715 1609 complete(&res->completion); 1716 1610 } 1717 1611 1612 + static int 1613 + smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key) 1614 + { 1615 + struct cifs_ses *ses; 1616 + u8 *ses_enc_key; 1617 + 1618 + spin_lock(&cifs_tcp_ses_lock); 1619 + list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { 1620 + if (ses->Suid != ses_id) 1621 + continue; 1622 + ses_enc_key = enc ? ses->smb3encryptionkey : 1623 + ses->smb3decryptionkey; 1624 + memcpy(key, ses_enc_key, SMB3_SIGN_KEY_SIZE); 1625 + spin_unlock(&cifs_tcp_ses_lock); 1626 + return 0; 1627 + } 1628 + spin_unlock(&cifs_tcp_ses_lock); 1629 + 1630 + return 1; 1631 + } 1718 1632 /* 1719 1633 * Encrypt or decrypt @rqst message. @rqst has the following format: 1720 1634 * iov[0] - transform header (associate data), ··· 1748 1622 struct smb2_transform_hdr *tr_hdr = 1749 1623 (struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base; 1750 1624 unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24; 1751 - struct cifs_ses *ses; 1752 1625 int rc = 0; 1753 1626 struct scatterlist *sg; 1754 1627 u8 sign[SMB2_SIGNATURE_SIZE] = {}; 1628 + u8 key[SMB3_SIGN_KEY_SIZE]; 1755 1629 struct aead_request *req; 1756 1630 char *iv; 1757 1631 unsigned int iv_len; ··· 1761 1635 1762 1636 init_completion(&result.completion); 1763 1637 1764 - ses = smb2_find_smb_ses(server, tr_hdr->SessionId); 1765 - if (!ses) { 1766 - cifs_dbg(VFS, "%s: Could not find session\n", __func__); 1638 + rc = smb2_get_enc_key(server, tr_hdr->SessionId, enc, key); 1639 + if (rc) { 1640 + cifs_dbg(VFS, "%s: Could not get %scryption key\n", __func__, 1641 + enc ? "en" : "de"); 1767 1642 return 0; 1768 1643 } 1769 1644 ··· 1776 1649 1777 1650 tfm = enc ? server->secmech.ccmaesencrypt : 1778 1651 server->secmech.ccmaesdecrypt; 1779 - rc = crypto_aead_setkey(tfm, enc ? ses->smb3encryptionkey : 1780 - ses->smb3decryptionkey, SMB3_SIGN_KEY_SIZE); 1652 + rc = crypto_aead_setkey(tfm, key, SMB3_SIGN_KEY_SIZE); 1781 1653 if (rc) { 1782 1654 cifs_dbg(VFS, "%s: Failed to set aead key %d\n", __func__, rc); 1783 1655 return rc; ··· 2380 2254 .clone_range = smb2_clone_range, 2381 2255 .wp_retry_size = smb2_wp_retry_size, 2382 2256 .dir_needs_close = smb2_dir_needs_close, 2257 + .get_dfs_refer = smb2_get_dfs_refer, 2258 + .select_sectype = smb2_select_sectype, 2383 2259 }; 2384 2260 2385 2261 struct smb_version_operations smb21_operations = { ··· 2463 2335 .wp_retry_size = smb2_wp_retry_size, 2464 2336 .dir_needs_close = smb2_dir_needs_close, 2465 2337 .enum_snapshots = smb3_enum_snapshots, 2338 + .get_dfs_refer = smb2_get_dfs_refer, 2339 + .select_sectype = smb2_select_sectype, 2466 2340 }; 2467 2341 2468 2342 struct smb_version_operations smb30_operations = { ··· 2556 2426 .free_transform_rq = smb3_free_transform_rq, 2557 2427 .is_transform_hdr = smb3_is_transform_hdr, 2558 2428 .receive_transform = smb3_receive_transform, 2429 + .get_dfs_refer = smb2_get_dfs_refer, 2430 + .select_sectype = smb2_select_sectype, 2559 2431 }; 2560 2432 2561 2433 #ifdef CONFIG_CIFS_SMB311 ··· 2650 2518 .free_transform_rq = smb3_free_transform_rq, 2651 2519 .is_transform_hdr = smb3_is_transform_hdr, 2652 2520 .receive_transform = smb3_receive_transform, 2521 + .get_dfs_refer = smb2_get_dfs_refer, 2522 + .select_sectype = smb2_select_sectype, 2653 2523 }; 2654 2524 #endif /* CIFS_SMB311 */ 2655 2525
+129 -23
fs/cifs/smb2pdu.c
··· 620 620 621 621 rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, 622 622 FSCTL_VALIDATE_NEGOTIATE_INFO, true /* is_fsctl */, 623 + false /* use_ipc */, 623 624 (char *)&vneg_inbuf, sizeof(struct validate_negotiate_info_req), 624 625 (char **)&pneg_rsp, &rsplen); 625 626 ··· 655 654 vneg_out: 656 655 cifs_dbg(VFS, "protocol revalidation - security settings mismatch\n"); 657 656 return -EIO; 657 + } 658 + 659 + enum securityEnum 660 + smb2_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested) 661 + { 662 + switch (requested) { 663 + case Kerberos: 664 + case RawNTLMSSP: 665 + return requested; 666 + case NTLMv2: 667 + return RawNTLMSSP; 668 + case Unspecified: 669 + if (server->sec_ntlmssp && 670 + (global_secflags & CIFSSEC_MAY_NTLMSSP)) 671 + return RawNTLMSSP; 672 + if ((server->sec_kerberos || server->sec_mskerberos) && 673 + (global_secflags & CIFSSEC_MAY_KRB5)) 674 + return Kerberos; 675 + /* Fallthrough */ 676 + default: 677 + return Unspecified; 678 + } 658 679 } 659 680 660 681 struct SMB2_sess_data { ··· 1031 1008 static int 1032 1009 SMB2_select_sec(struct cifs_ses *ses, struct SMB2_sess_data *sess_data) 1033 1010 { 1034 - if (ses->sectype != Kerberos && ses->sectype != RawNTLMSSP) 1035 - ses->sectype = RawNTLMSSP; 1011 + int type; 1036 1012 1037 - switch (ses->sectype) { 1013 + type = smb2_select_sectype(ses->server, ses->sectype); 1014 + cifs_dbg(FYI, "sess setup type %d\n", type); 1015 + if (type == Unspecified) { 1016 + cifs_dbg(VFS, 1017 + "Unable to select appropriate authentication method!"); 1018 + return -EINVAL; 1019 + } 1020 + 1021 + switch (type) { 1038 1022 case Kerberos: 1039 1023 sess_data->func = SMB2_auth_kerberos; 1040 1024 break; ··· 1049 1019 sess_data->func = SMB2_sess_auth_rawntlmssp_negotiate; 1050 1020 break; 1051 1021 default: 1052 - cifs_dbg(VFS, "secType %d not supported!\n", ses->sectype); 1022 + cifs_dbg(VFS, "secType %d not supported!\n", type); 1053 1023 return -EOPNOTSUPP; 1054 1024 } 1055 1025 ··· 1197 1167 1198 1168 /* since no tcon, smb2_init can not do this, so do here */ 1199 1169 req->hdr.sync_hdr.SessionId = ses->Suid; 1200 - /* if (ses->server->sec_mode & SECMODE_SIGN_REQUIRED) 1201 - req->hdr.Flags |= SMB2_FLAGS_SIGNED; */ 1170 + if (ses->server->sign) 1171 + req->hdr.sync_hdr.Flags |= SMB2_FLAGS_SIGNED; 1202 1172 } else if (encryption_required(tcon)) 1203 1173 flags |= CIFS_TRANSFORM_REQ; 1204 1174 ··· 1557 1527 return 0; 1558 1528 } 1559 1529 1530 + static int 1531 + alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len, 1532 + const char *treename, const __le16 *path) 1533 + { 1534 + int treename_len, path_len; 1535 + struct nls_table *cp; 1536 + const __le16 sep[] = {cpu_to_le16('\\'), cpu_to_le16(0x0000)}; 1537 + 1538 + /* 1539 + * skip leading "\\" 1540 + */ 1541 + treename_len = strlen(treename); 1542 + if (treename_len < 2 || !(treename[0] == '\\' && treename[1] == '\\')) 1543 + return -EINVAL; 1544 + 1545 + treename += 2; 1546 + treename_len -= 2; 1547 + 1548 + path_len = UniStrnlen((wchar_t *)path, PATH_MAX); 1549 + 1550 + /* 1551 + * make room for one path separator between the treename and 1552 + * path 1553 + */ 1554 + *out_len = treename_len + 1 + path_len; 1555 + 1556 + /* 1557 + * final path needs to be null-terminated UTF16 with a 1558 + * size aligned to 8 1559 + */ 1560 + 1561 + *out_size = roundup((*out_len+1)*2, 8); 1562 + *out_path = kzalloc(*out_size, GFP_KERNEL); 1563 + if (!*out_path) 1564 + return -ENOMEM; 1565 + 1566 + cp = load_nls_default(); 1567 + cifs_strtoUTF16(*out_path, treename, treename_len, cp); 1568 + UniStrcat(*out_path, sep); 1569 + UniStrcat(*out_path, path); 1570 + unload_nls(cp); 1571 + 1572 + return 0; 1573 + } 1574 + 1560 1575 int 1561 1576 SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, 1562 1577 __u8 *oplock, struct smb2_file_all_info *buf, ··· 1650 1575 req->ShareAccess = FILE_SHARE_ALL_LE; 1651 1576 req->CreateDisposition = cpu_to_le32(oparms->disposition); 1652 1577 req->CreateOptions = cpu_to_le32(oparms->create_options & CREATE_OPTIONS_MASK); 1653 - uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2; 1654 - /* do not count rfc1001 len field */ 1655 - req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req) - 4); 1656 1578 1657 1579 iov[0].iov_base = (char *)req; 1658 1580 /* 4 for rfc1002 length field */ 1659 1581 iov[0].iov_len = get_rfc1002_length(req) + 4; 1660 - 1661 - /* MUST set path len (NameLength) to 0 opening root of share */ 1662 - req->NameLength = cpu_to_le16(uni_path_len - 2); 1663 1582 /* -1 since last byte is buf[0] which is sent below (path) */ 1664 1583 iov[0].iov_len--; 1665 - if (uni_path_len % 8 != 0) { 1666 - copy_size = uni_path_len / 8 * 8; 1667 - if (copy_size < uni_path_len) 1668 - copy_size += 8; 1669 1584 1670 - copy_path = kzalloc(copy_size, GFP_KERNEL); 1671 - if (!copy_path) 1672 - return -ENOMEM; 1673 - memcpy((char *)copy_path, (const char *)path, 1674 - uni_path_len); 1585 + req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req) - 4); 1586 + 1587 + /* [MS-SMB2] 2.2.13 NameOffset: 1588 + * If SMB2_FLAGS_DFS_OPERATIONS is set in the Flags field of 1589 + * the SMB2 header, the file name includes a prefix that will 1590 + * be processed during DFS name normalization as specified in 1591 + * section 3.3.5.9. Otherwise, the file name is relative to 1592 + * the share that is identified by the TreeId in the SMB2 1593 + * header. 1594 + */ 1595 + if (tcon->share_flags & SHI1005_FLAGS_DFS) { 1596 + int name_len; 1597 + 1598 + req->hdr.sync_hdr.Flags |= SMB2_FLAGS_DFS_OPERATIONS; 1599 + rc = alloc_path_with_tree_prefix(&copy_path, &copy_size, 1600 + &name_len, 1601 + tcon->treeName, path); 1602 + if (rc) 1603 + return rc; 1604 + req->NameLength = cpu_to_le16(name_len * 2); 1675 1605 uni_path_len = copy_size; 1676 1606 path = copy_path; 1607 + } else { 1608 + uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2; 1609 + /* MUST set path len (NameLength) to 0 opening root of share */ 1610 + req->NameLength = cpu_to_le16(uni_path_len - 2); 1611 + if (uni_path_len % 8 != 0) { 1612 + copy_size = roundup(uni_path_len, 8); 1613 + copy_path = kzalloc(copy_size, GFP_KERNEL); 1614 + if (!copy_path) 1615 + return -ENOMEM; 1616 + memcpy((char *)copy_path, (const char *)path, 1617 + uni_path_len); 1618 + uni_path_len = copy_size; 1619 + path = copy_path; 1620 + } 1677 1621 } 1678 1622 1679 1623 iov[1].iov_len = uni_path_len; ··· 1777 1683 */ 1778 1684 int 1779 1685 SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, 1780 - u64 volatile_fid, u32 opcode, bool is_fsctl, char *in_data, 1781 - u32 indatalen, char **out_data, u32 *plen /* returned data len */) 1686 + u64 volatile_fid, u32 opcode, bool is_fsctl, bool use_ipc, 1687 + char *in_data, u32 indatalen, 1688 + char **out_data, u32 *plen /* returned data len */) 1782 1689 { 1783 1690 struct smb2_ioctl_req *req; 1784 1691 struct smb2_ioctl_rsp *rsp; ··· 1816 1721 if (rc) 1817 1722 return rc; 1818 1723 1724 + if (use_ipc) { 1725 + if (ses->ipc_tid == 0) { 1726 + cifs_small_buf_release(req); 1727 + return -ENOTCONN; 1728 + } 1729 + 1730 + cifs_dbg(FYI, "replacing tid 0x%x with IPC tid 0x%x\n", 1731 + req->hdr.sync_hdr.TreeId, ses->ipc_tid); 1732 + req->hdr.sync_hdr.TreeId = ses->ipc_tid; 1733 + } 1819 1734 if (encryption_required(tcon)) 1820 1735 flags |= CIFS_TRANSFORM_REQ; 1821 1736 ··· 1948 1843 1949 1844 rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid, 1950 1845 FSCTL_SET_COMPRESSION, true /* is_fsctl */, 1846 + false /* use_ipc */, 1951 1847 (char *)&fsctl_input /* data input */, 1952 1848 2 /* in data len */, &ret_data /* out data */, NULL); 1953 1849
+8
fs/cifs/smb2pdu.h
··· 695 695 /* Integrity flags for above */ 696 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 706 /* See MS-SMB2 2.2.31.3 */ 699 707 struct network_resiliency_req { 700 708 __le32 Timeout;
+4 -1
fs/cifs/smb2proto.h
··· 121 121 struct smb2_err_rsp **err_buf); 122 122 extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, 123 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 126 char **out_data, u32 *plen /* returned data len */); 126 127 extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, 127 128 u64 persistent_file_id, u64 volatile_file_id); ··· 181 180 __u8 *lease_key, const __le32 lease_state); 182 181 extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *); 183 182 183 + extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *, 184 + enum securityEnum); 184 185 #endif /* _SMB2PROTO_H */