.. | .. |
---|
| 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, |
---|