| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * SMB1 (CIFS) version specific operations |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (c) 2012, Jeff Layton <jlayton@redhat.com> |
|---|
| 5 | | - * |
|---|
| 6 | | - * This library is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License v2 as published |
|---|
| 8 | | - * by the Free Software Foundation. |
|---|
| 9 | | - * |
|---|
| 10 | | - * This library is distributed in the hope that it will be useful, |
|---|
| 11 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
|---|
| 13 | | - * the GNU Lesser General Public License for more details. |
|---|
| 14 | | - * |
|---|
| 15 | | - * You should have received a copy of the GNU Lesser General Public License |
|---|
| 16 | | - * along with this library; if not, write to the Free Software |
|---|
| 17 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 18 | 6 | */ |
|---|
| 19 | 7 | |
|---|
| 20 | 8 | #include <linux/pagemap.h> |
|---|
| .. | .. |
|---|
| 117 | 105 | } |
|---|
| 118 | 106 | |
|---|
| 119 | 107 | static void |
|---|
| 120 | | -cifs_add_credits(struct TCP_Server_Info *server, const unsigned int add, |
|---|
| 121 | | - const int optype) |
|---|
| 108 | +cifs_add_credits(struct TCP_Server_Info *server, |
|---|
| 109 | + const struct cifs_credits *credits, const int optype) |
|---|
| 122 | 110 | { |
|---|
| 123 | 111 | spin_lock(&server->req_lock); |
|---|
| 124 | | - server->credits += add; |
|---|
| 112 | + server->credits += credits->value; |
|---|
| 125 | 113 | server->in_flight--; |
|---|
| 126 | 114 | spin_unlock(&server->req_lock); |
|---|
| 127 | 115 | wake_up(&server->request_q); |
|---|
| .. | .. |
|---|
| 259 | 247 | /* check for plausible wct, bcc and t2 data and parm sizes */ |
|---|
| 260 | 248 | /* check for parm and data offset going beyond end of smb */ |
|---|
| 261 | 249 | if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */ |
|---|
| 262 | | - cifs_dbg(FYI, "invalid transact2 word count\n"); |
|---|
| 250 | + cifs_dbg(FYI, "Invalid transact2 word count\n"); |
|---|
| 263 | 251 | return -EINVAL; |
|---|
| 264 | 252 | } |
|---|
| 265 | 253 | |
|---|
| .. | .. |
|---|
| 516 | 504 | } |
|---|
| 517 | 505 | |
|---|
| 518 | 506 | static void |
|---|
| 519 | | -cifs_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon) |
|---|
| 507 | +cifs_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon, |
|---|
| 508 | + struct cifs_sb_info *cifs_sb) |
|---|
| 520 | 509 | { |
|---|
| 521 | 510 | CIFSSMBQFSDeviceInfo(xid, tcon); |
|---|
| 522 | 511 | CIFSSMBQFSAttributeInfo(xid, tcon); |
|---|
| .. | .. |
|---|
| 577 | 566 | oparms.tcon = tcon; |
|---|
| 578 | 567 | oparms.cifs_sb = cifs_sb; |
|---|
| 579 | 568 | oparms.desired_access = FILE_READ_ATTRIBUTES; |
|---|
| 580 | | - oparms.create_options = 0; |
|---|
| 569 | + oparms.create_options = cifs_create_options(cifs_sb, 0); |
|---|
| 581 | 570 | oparms.disposition = FILE_OPEN; |
|---|
| 582 | 571 | oparms.path = full_path; |
|---|
| 583 | 572 | oparms.fid = &fid; |
|---|
| .. | .. |
|---|
| 699 | 688 | dosattrs = cifsInode->cifsAttrs|ATTR_READONLY; |
|---|
| 700 | 689 | info.Attributes = cpu_to_le32(dosattrs); |
|---|
| 701 | 690 | rc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info, cifs_sb->local_nls, |
|---|
| 702 | | - cifs_remap(cifs_sb)); |
|---|
| 691 | + cifs_sb); |
|---|
| 703 | 692 | if (rc == 0) |
|---|
| 704 | 693 | cifsInode->cifsAttrs = dosattrs; |
|---|
| 705 | 694 | } |
|---|
| .. | .. |
|---|
| 777 | 766 | struct cifs_tcon *tcon; |
|---|
| 778 | 767 | |
|---|
| 779 | 768 | /* if the file is already open for write, just use that fileid */ |
|---|
| 780 | | - open_file = find_writable_file(cinode, true); |
|---|
| 769 | + open_file = find_writable_file(cinode, FIND_WR_FSUID_ONLY); |
|---|
| 781 | 770 | if (open_file) { |
|---|
| 782 | 771 | fid.netfid = open_file->fid.netfid; |
|---|
| 783 | 772 | netpid = open_file->pid; |
|---|
| .. | .. |
|---|
| 794 | 783 | tcon = tlink_tcon(tlink); |
|---|
| 795 | 784 | |
|---|
| 796 | 785 | rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf, cifs_sb->local_nls, |
|---|
| 797 | | - cifs_remap(cifs_sb)); |
|---|
| 786 | + cifs_sb); |
|---|
| 798 | 787 | if (rc == 0) { |
|---|
| 799 | 788 | cinode->cifsAttrs = le32_to_cpu(buf->Attributes); |
|---|
| 800 | 789 | goto out; |
|---|
| .. | .. |
|---|
| 805 | 794 | oparms.tcon = tcon; |
|---|
| 806 | 795 | oparms.cifs_sb = cifs_sb; |
|---|
| 807 | 796 | oparms.desired_access = SYNCHRONIZE | FILE_WRITE_ATTRIBUTES; |
|---|
| 808 | | - oparms.create_options = CREATE_NOT_DIR; |
|---|
| 797 | + oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR); |
|---|
| 809 | 798 | oparms.disposition = FILE_OPEN; |
|---|
| 810 | 799 | oparms.path = full_path; |
|---|
| 811 | 800 | oparms.fid = &fid; |
|---|
| .. | .. |
|---|
| 884 | 873 | |
|---|
| 885 | 874 | static int |
|---|
| 886 | 875 | cifs_queryfs(const unsigned int xid, struct cifs_tcon *tcon, |
|---|
| 887 | | - struct kstatfs *buf) |
|---|
| 876 | + struct cifs_sb_info *cifs_sb, struct kstatfs *buf) |
|---|
| 888 | 877 | { |
|---|
| 889 | 878 | int rc = -EOPNOTSUPP; |
|---|
| 890 | 879 | |
|---|
| .. | .. |
|---|
| 930 | 919 | { |
|---|
| 931 | 920 | #ifdef CONFIG_CIFS_DFS_UPCALL |
|---|
| 932 | 921 | int rc; |
|---|
| 933 | | - unsigned int num_referrals = 0; |
|---|
| 934 | | - struct dfs_info3_param *referrals = NULL; |
|---|
| 922 | + struct dfs_info3_param referral = {0}; |
|---|
| 935 | 923 | |
|---|
| 936 | | - rc = get_dfs_path(xid, tcon->ses, searchName, nls_codepage, |
|---|
| 937 | | - &num_referrals, &referrals, 0); |
|---|
| 924 | + rc = get_dfs_path(xid, tcon->ses, searchName, nls_codepage, &referral, |
|---|
| 925 | + 0); |
|---|
| 938 | 926 | |
|---|
| 939 | | - if (!rc && num_referrals > 0) { |
|---|
| 940 | | - *symlinkinfo = kstrndup(referrals->node_name, |
|---|
| 941 | | - strlen(referrals->node_name), |
|---|
| 927 | + if (!rc) { |
|---|
| 928 | + *symlinkinfo = kstrndup(referral.node_name, |
|---|
| 929 | + strlen(referral.node_name), |
|---|
| 942 | 930 | GFP_KERNEL); |
|---|
| 931 | + free_dfs_info_param(&referral); |
|---|
| 943 | 932 | if (!*symlinkinfo) |
|---|
| 944 | 933 | rc = -ENOMEM; |
|---|
| 945 | | - free_dfs_info_array(referrals, num_referrals); |
|---|
| 946 | 934 | } |
|---|
| 947 | 935 | return rc; |
|---|
| 948 | 936 | #else /* No DFS support */ |
|---|
| .. | .. |
|---|
| 952 | 940 | |
|---|
| 953 | 941 | static int |
|---|
| 954 | 942 | cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, |
|---|
| 955 | | - const char *full_path, char **target_path, |
|---|
| 956 | | - struct cifs_sb_info *cifs_sb) |
|---|
| 943 | + struct cifs_sb_info *cifs_sb, const char *full_path, |
|---|
| 944 | + char **target_path, bool is_reparse_point) |
|---|
| 957 | 945 | { |
|---|
| 958 | 946 | int rc; |
|---|
| 959 | 947 | int oplock = 0; |
|---|
| .. | .. |
|---|
| 961 | 949 | struct cifs_open_parms oparms; |
|---|
| 962 | 950 | |
|---|
| 963 | 951 | cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); |
|---|
| 952 | + |
|---|
| 953 | + if (is_reparse_point) { |
|---|
| 954 | + cifs_dbg(VFS, "reparse points not handled for SMB1 symlinks\n"); |
|---|
| 955 | + return -EOPNOTSUPP; |
|---|
| 956 | + } |
|---|
| 964 | 957 | |
|---|
| 965 | 958 | /* Check for unix extensions */ |
|---|
| 966 | 959 | if (cap_unix(tcon->ses)) { |
|---|
| .. | .. |
|---|
| 978 | 971 | oparms.tcon = tcon; |
|---|
| 979 | 972 | oparms.cifs_sb = cifs_sb; |
|---|
| 980 | 973 | oparms.desired_access = FILE_READ_ATTRIBUTES; |
|---|
| 981 | | - oparms.create_options = OPEN_REPARSE_POINT; |
|---|
| 974 | + oparms.create_options = cifs_create_options(cifs_sb, |
|---|
| 975 | + OPEN_REPARSE_POINT); |
|---|
| 982 | 976 | oparms.disposition = FILE_OPEN; |
|---|
| 983 | 977 | oparms.path = full_path; |
|---|
| 984 | 978 | oparms.fid = &fid; |
|---|
| .. | .. |
|---|
| 1028 | 1022 | |
|---|
| 1029 | 1023 | return false; |
|---|
| 1030 | 1024 | } |
|---|
| 1025 | + |
|---|
| 1026 | +static int |
|---|
| 1027 | +cifs_make_node(unsigned int xid, struct inode *inode, |
|---|
| 1028 | + struct dentry *dentry, struct cifs_tcon *tcon, |
|---|
| 1029 | + char *full_path, umode_t mode, dev_t dev) |
|---|
| 1030 | +{ |
|---|
| 1031 | + struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
|---|
| 1032 | + struct inode *newinode = NULL; |
|---|
| 1033 | + int rc = -EPERM; |
|---|
| 1034 | + FILE_ALL_INFO *buf = NULL; |
|---|
| 1035 | + struct cifs_io_parms io_parms; |
|---|
| 1036 | + __u32 oplock = 0; |
|---|
| 1037 | + struct cifs_fid fid; |
|---|
| 1038 | + struct cifs_open_parms oparms; |
|---|
| 1039 | + unsigned int bytes_written; |
|---|
| 1040 | + struct win_dev *pdev; |
|---|
| 1041 | + struct kvec iov[2]; |
|---|
| 1042 | + |
|---|
| 1043 | + if (tcon->unix_ext) { |
|---|
| 1044 | + /* |
|---|
| 1045 | + * SMB1 Unix Extensions: requires server support but |
|---|
| 1046 | + * works with all special files |
|---|
| 1047 | + */ |
|---|
| 1048 | + struct cifs_unix_set_info_args args = { |
|---|
| 1049 | + .mode = mode & ~current_umask(), |
|---|
| 1050 | + .ctime = NO_CHANGE_64, |
|---|
| 1051 | + .atime = NO_CHANGE_64, |
|---|
| 1052 | + .mtime = NO_CHANGE_64, |
|---|
| 1053 | + .device = dev, |
|---|
| 1054 | + }; |
|---|
| 1055 | + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { |
|---|
| 1056 | + args.uid = current_fsuid(); |
|---|
| 1057 | + args.gid = current_fsgid(); |
|---|
| 1058 | + } else { |
|---|
| 1059 | + args.uid = INVALID_UID; /* no change */ |
|---|
| 1060 | + args.gid = INVALID_GID; /* no change */ |
|---|
| 1061 | + } |
|---|
| 1062 | + rc = CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, |
|---|
| 1063 | + cifs_sb->local_nls, |
|---|
| 1064 | + cifs_remap(cifs_sb)); |
|---|
| 1065 | + if (rc) |
|---|
| 1066 | + goto out; |
|---|
| 1067 | + |
|---|
| 1068 | + rc = cifs_get_inode_info_unix(&newinode, full_path, |
|---|
| 1069 | + inode->i_sb, xid); |
|---|
| 1070 | + |
|---|
| 1071 | + if (rc == 0) |
|---|
| 1072 | + d_instantiate(dentry, newinode); |
|---|
| 1073 | + goto out; |
|---|
| 1074 | + } |
|---|
| 1075 | + |
|---|
| 1076 | + /* |
|---|
| 1077 | + * SMB1 SFU emulation: should work with all servers, but only |
|---|
| 1078 | + * support block and char device (no socket & fifo) |
|---|
| 1079 | + */ |
|---|
| 1080 | + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) |
|---|
| 1081 | + goto out; |
|---|
| 1082 | + |
|---|
| 1083 | + if (!S_ISCHR(mode) && !S_ISBLK(mode)) |
|---|
| 1084 | + goto out; |
|---|
| 1085 | + |
|---|
| 1086 | + cifs_dbg(FYI, "sfu compat create special file\n"); |
|---|
| 1087 | + |
|---|
| 1088 | + buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); |
|---|
| 1089 | + if (buf == NULL) { |
|---|
| 1090 | + rc = -ENOMEM; |
|---|
| 1091 | + goto out; |
|---|
| 1092 | + } |
|---|
| 1093 | + |
|---|
| 1094 | + oparms.tcon = tcon; |
|---|
| 1095 | + oparms.cifs_sb = cifs_sb; |
|---|
| 1096 | + oparms.desired_access = GENERIC_WRITE; |
|---|
| 1097 | + oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR | |
|---|
| 1098 | + CREATE_OPTION_SPECIAL); |
|---|
| 1099 | + oparms.disposition = FILE_CREATE; |
|---|
| 1100 | + oparms.path = full_path; |
|---|
| 1101 | + oparms.fid = &fid; |
|---|
| 1102 | + oparms.reconnect = false; |
|---|
| 1103 | + |
|---|
| 1104 | + if (tcon->ses->server->oplocks) |
|---|
| 1105 | + oplock = REQ_OPLOCK; |
|---|
| 1106 | + else |
|---|
| 1107 | + oplock = 0; |
|---|
| 1108 | + rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, buf); |
|---|
| 1109 | + if (rc) |
|---|
| 1110 | + goto out; |
|---|
| 1111 | + |
|---|
| 1112 | + /* |
|---|
| 1113 | + * BB Do not bother to decode buf since no local inode yet to put |
|---|
| 1114 | + * timestamps in, but we can reuse it safely. |
|---|
| 1115 | + */ |
|---|
| 1116 | + |
|---|
| 1117 | + pdev = (struct win_dev *)buf; |
|---|
| 1118 | + io_parms.pid = current->tgid; |
|---|
| 1119 | + io_parms.tcon = tcon; |
|---|
| 1120 | + io_parms.offset = 0; |
|---|
| 1121 | + io_parms.length = sizeof(struct win_dev); |
|---|
| 1122 | + iov[1].iov_base = buf; |
|---|
| 1123 | + iov[1].iov_len = sizeof(struct win_dev); |
|---|
| 1124 | + if (S_ISCHR(mode)) { |
|---|
| 1125 | + memcpy(pdev->type, "IntxCHR", 8); |
|---|
| 1126 | + pdev->major = cpu_to_le64(MAJOR(dev)); |
|---|
| 1127 | + pdev->minor = cpu_to_le64(MINOR(dev)); |
|---|
| 1128 | + rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms, |
|---|
| 1129 | + &bytes_written, iov, 1); |
|---|
| 1130 | + } else if (S_ISBLK(mode)) { |
|---|
| 1131 | + memcpy(pdev->type, "IntxBLK", 8); |
|---|
| 1132 | + pdev->major = cpu_to_le64(MAJOR(dev)); |
|---|
| 1133 | + pdev->minor = cpu_to_le64(MINOR(dev)); |
|---|
| 1134 | + rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms, |
|---|
| 1135 | + &bytes_written, iov, 1); |
|---|
| 1136 | + } |
|---|
| 1137 | + tcon->ses->server->ops->close(xid, tcon, &fid); |
|---|
| 1138 | + d_drop(dentry); |
|---|
| 1139 | + |
|---|
| 1140 | + /* FIXME: add code here to set EAs */ |
|---|
| 1141 | +out: |
|---|
| 1142 | + kfree(buf); |
|---|
| 1143 | + return rc; |
|---|
| 1144 | +} |
|---|
| 1145 | + |
|---|
| 1146 | + |
|---|
| 1031 | 1147 | |
|---|
| 1032 | 1148 | struct smb_version_operations smb1_operations = { |
|---|
| 1033 | 1149 | .send_cancel = send_nt_cancel, |
|---|
| .. | .. |
|---|
| 1107 | 1223 | .query_all_EAs = CIFSSMBQAllEAs, |
|---|
| 1108 | 1224 | .set_EA = CIFSSMBSetEA, |
|---|
| 1109 | 1225 | #endif /* CIFS_XATTR */ |
|---|
| 1110 | | -#ifdef CONFIG_CIFS_ACL |
|---|
| 1111 | 1226 | .get_acl = get_cifs_acl, |
|---|
| 1112 | 1227 | .get_acl_by_fid = get_cifs_acl_by_fid, |
|---|
| 1113 | 1228 | .set_acl = set_cifs_acl, |
|---|
| 1114 | | -#endif /* CIFS_ACL */ |
|---|
| 1229 | + .make_node = cifs_make_node, |
|---|
| 1115 | 1230 | }; |
|---|
| 1116 | 1231 | |
|---|
| 1117 | 1232 | struct smb_version_values smb1_values = { |
|---|
| 1118 | 1233 | .version_string = SMB1_VERSION_STRING, |
|---|
| 1234 | + .protocol_id = SMB10_PROT_ID, |
|---|
| 1119 | 1235 | .large_lock_type = LOCKING_ANDX_LARGE_FILES, |
|---|
| 1120 | 1236 | .exclusive_lock_type = 0, |
|---|
| 1121 | 1237 | .shared_lock_type = LOCKING_ANDX_SHARED_LOCK, |
|---|