Pull more cifs updates from Steve French: "12 cifs/smb3 fixes, 2 for stable. - add support for idsfromsid on create and chgrp/chown allowing ability to save owner information more naturally for some workloads - improve query info (getattr) when SMB3.1.1 posix extensions are negotiated by using new query info level" * tag '5.8-rc-smb3-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6: smb3: Add debug message for new file creation with idsfromsid mount option cifs: fix chown and chgrp when idsfromsid mount option enabled smb3: allow uid and gid owners to be set on create with idsfromsid mount option smb311: Add tracepoints for new compound posix query info smb311: add support for using info level for posix extensions query smb311: Add support for lookup with posix extensions query info smb311: Add support for SMB311 query info (non-compounded) SMB311: Add support for query info using posix extensions (level 100) smb3: add indatalen that can be a non-zero value to calculation of credit charge in smb2 ioctl smb3: fix typo in mount options displayed in /proc/mounts cifs: Add get_security_type_str function to return sec type. smb3: extend fscache mount volume coherency check
Unified · Split
| @@ -53,13 +53,6 @@ const struct fscache_cookie_def cifs_fscache_server_index_def = { · 52 unmodified lines | ||
| 53 | 53 | .type = FSCACHE_COOKIE_TYPE_INDEX, |
| 54 | 54 | }; |
| 55 | 55 | |
| 56 | −/* | |
| 57 | − * Auxiliary data attached to CIFS superblock within the cache | |
| 58 | − */ | |
| 59 | −struct cifs_fscache_super_auxdata { | |
| 60 | − u64 resource_id; /* unique server resource id */ | |
| 61 | −}; | |
| 62 | − | |
| 63 | 56 | char *extract_sharename(const char *treename) |
| 64 | 57 | { |
| 65 | 58 | const char *src; |
| @@ -98,6 +91,8 @@ fscache_checkaux cifs_fscache_super_check_aux(void *cookie_netfs_data, · 32 unmodified lines | ||
| 98 | 91 | |
| 99 | 92 | memset(&auxdata, 0, sizeof(auxdata)); |
| 100 | 93 | auxdata.resource_id = tcon->resource_id; |
| 94 | + auxdata.vol_create_time = tcon->vol_create_time; | |
| 95 | + auxdata.vol_serial_number = tcon->vol_serial_number; | |
| 101 | 96 | |
| 102 | 97 | if (memcmp(data, &auxdata, datalen) != 0) |
| 103 | 98 | return FSCACHE_CHECKAUX_OBSOLETE; |
| @@ -221,8 +221,6 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) · 220 unmodified lines | ||
| 221 | 221 | struct cifs_ses *ses; |
| 222 | 222 | struct cifs_tcon *tcon; |
| 223 | 223 | int i, j; |
| 224 | − const char *security_types[] = {"Unspecified", "LANMAN", "NTLM", | |
| 225 | − "NTLMv2", "RawNTLMSSP", "Kerberos"}; | |
| 226 | 224 | |
| 227 | 225 | seq_puts(m, |
| 228 | 226 | "Display Internal CIFS Data Structures for Debugging\n" |
| @@ -379,7 +377,7 @@ skip_rdma: · 150 unmodified lines | ||
| 379 | 377 | } |
| 380 | 378 | |
| 381 | 379 | seq_printf(m,"Security type: %s\n", |
| 382 | − security_types[server->ops->select_sectype(server, ses->sectype)]); | |
| 380 | + get_security_type_str(server->ops->select_sectype(server, ses->sectype))); | |
| 383 | 381 | |
| 384 | 382 | if (server->rdma) |
| 385 | 383 | seq_printf(m, "RDMA\n\t"); |
| @@ -849,6 +849,28 @@ unsigned int setup_special_mode_ACE(struct cifs_ace *pntace, __u64 nmode) · 848 unmodified lines | ||
| 849 | 849 | return ace_size; |
| 850 | 850 | } |
| 851 | 851 | |
| 852 | +unsigned int setup_special_user_owner_ACE(struct cifs_ace *pntace) | |
| 853 | +{ | |
| 854 | + int i; | |
| 855 | + unsigned int ace_size = 28; | |
| 856 | + | |
| 857 | + pntace->type = ACCESS_ALLOWED_ACE_TYPE; | |
| 858 | + pntace->flags = 0x0; | |
| 859 | + pntace->access_req = cpu_to_le32(GENERIC_ALL); | |
| 860 | + pntace->sid.num_subauth = 3; | |
| 861 | + pntace->sid.revision = 1; | |
| 862 | + for (i = 0; i < NUM_AUTHS; i++) | |
| 863 | + pntace->sid.authority[i] = sid_unix_NFS_users.authority[i]; | |
| 864 | + | |
| 865 | + pntace->sid.sub_auth[0] = sid_unix_NFS_users.sub_auth[0]; | |
| 866 | + pntace->sid.sub_auth[1] = sid_unix_NFS_users.sub_auth[1]; | |
| 867 | + pntace->sid.sub_auth[2] = cpu_to_le32(current_fsgid().val); | |
| 868 | + | |
| 869 | + /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */ | |
| 870 | + pntace->size = cpu_to_le16(ace_size); | |
| 871 | + return ace_size; | |
| 872 | +} | |
| 873 | + | |
| 852 | 874 | static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid, |
| 853 | 875 | struct cifs_sid *pgrpsid, __u64 nmode, bool modefromsid) |
| 854 | 876 | { |
| @@ -978,7 +1000,7 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb, · 123 unmodified lines | ||
| 978 | 1000 | /* Convert permission bits from mode to equivalent CIFS ACL */ |
| 979 | 1001 | static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, |
| 980 | 1002 | __u32 secdesclen, __u64 nmode, kuid_t uid, kgid_t gid, |
| 981 | − bool mode_from_sid, int *aclflag) | |
| 1003 | + bool mode_from_sid, bool id_from_sid, int *aclflag) | |
| 982 | 1004 | { |
| 983 | 1005 | int rc = 0; |
| 984 | 1006 | __u32 dacloffset; |
| @@ -1019,12 +1041,23 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, · 34 unmodified lines | ||
| 1019 | 1041 | if (!nowner_sid_ptr) |
| 1020 | 1042 | return -ENOMEM; |
| 1021 | 1043 | id = from_kuid(&init_user_ns, uid); |
| 1022 | − rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr); | |
| 1023 | − if (rc) { | |
| 1024 | − cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n", | |
| 1025 | − __func__, rc, id); | |
| 1026 | − kfree(nowner_sid_ptr); | |
| 1027 | − return rc; | |
| 1044 | + if (id_from_sid) { | |
| 1045 | + struct owner_sid *osid = (struct owner_sid *)nowner_sid_ptr; | |
| 1046 | + /* Populate the user ownership fields S-1-5-88-1 */ | |
| 1047 | + osid->Revision = 1; | |
| 1048 | + osid->NumAuth = 3; | |
| 1049 | + osid->Authority[5] = 5; | |
| 1050 | + osid->SubAuthorities[0] = cpu_to_le32(88); | |
| 1051 | + osid->SubAuthorities[1] = cpu_to_le32(1); | |
| 1052 | + osid->SubAuthorities[2] = cpu_to_le32(id); | |
| 1053 | + } else { /* lookup sid with upcall */ | |
| 1054 | + rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr); | |
| 1055 | + if (rc) { | |
| 1056 | + cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n", | |
| 1057 | + __func__, rc, id); | |
| 1058 | + kfree(nowner_sid_ptr); | |
| 1059 | + return rc; | |
| 1060 | + } | |
| 1028 | 1061 | } |
| 1029 | 1062 | cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr); |
| 1030 | 1063 | kfree(nowner_sid_ptr); |
| @@ -1039,12 +1072,23 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, · 8 unmodified lines | ||
| 1039 | 1072 | if (!ngroup_sid_ptr) |
| 1040 | 1073 | return -ENOMEM; |
| 1041 | 1074 | id = from_kgid(&init_user_ns, gid); |
| 1042 | − rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr); | |
| 1043 | − if (rc) { | |
| 1044 | − cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n", | |
| 1045 | − __func__, rc, id); | |
| 1046 | − kfree(ngroup_sid_ptr); | |
| 1047 | − return rc; | |
| 1075 | + if (id_from_sid) { | |
| 1076 | + struct owner_sid *gsid = (struct owner_sid *)ngroup_sid_ptr; | |
| 1077 | + /* Populate the group ownership fields S-1-5-88-2 */ | |
| 1078 | + gsid->Revision = 1; | |
| 1079 | + gsid->NumAuth = 3; | |
| 1080 | + gsid->Authority[5] = 5; | |
| 1081 | + gsid->SubAuthorities[0] = cpu_to_le32(88); | |
| 1082 | + gsid->SubAuthorities[1] = cpu_to_le32(2); | |
| 1083 | + gsid->SubAuthorities[2] = cpu_to_le32(id); | |
| 1084 | + } else { /* lookup sid with upcall */ | |
| 1085 | + rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr); | |
| 1086 | + if (rc) { | |
| 1087 | + cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n", | |
| 1088 | + __func__, rc, id); | |
| 1089 | + kfree(ngroup_sid_ptr); | |
| 1090 | + return rc; | |
| 1091 | + } | |
| 1048 | 1092 | } |
| 1049 | 1093 | cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr); |
| 1050 | 1094 | kfree(ngroup_sid_ptr); |
| @@ -1247,7 +1291,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode, · 196 unmodified lines | ||
| 1247 | 1291 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
| 1248 | 1292 | struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); |
| 1249 | 1293 | struct smb_version_operations *ops; |
| 1250 | − bool mode_from_sid; | |
| 1294 | + bool mode_from_sid, id_from_sid; | |
| 1251 | 1295 | |
| 1252 | 1296 | if (IS_ERR(tlink)) |
| 1253 | 1297 | return PTR_ERR(tlink); |
| @@ -1290,8 +1334,13 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode, · 36 unmodified lines | ||
| 1290 | 1334 | else |
| 1291 | 1335 | mode_from_sid = false; |
| 1292 | 1336 | |
| 1337 | + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) | |
| 1338 | + id_from_sid = true; | |
| 1339 | + else | |
| 1340 | + id_from_sid = false; | |
| 1341 | + | |
| 1293 | 1342 | rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid, |
| 1294 | − mode_from_sid, &aclflag); | |
| 1343 | + mode_from_sid, id_from_sid, &aclflag); | |
| 1295 | 1344 | |
| 1296 | 1345 | cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc); |
| 1297 | 1346 | |
| @@ -176,6 +176,21 @@ struct smb3_acl { · 175 unmodified lines | ||
| 176 | 176 | __le16 Sbz2; /* MBZ */ |
| 177 | 177 | } __packed; |
| 178 | 178 | |
| 179 | +/* | |
| 180 | + * Used to store the special 'NFS SIDs' used to persist the POSIX uid and gid | |
| 181 | + * See See http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx | |
| 182 | + */ | |
| 183 | +struct owner_sid { | |
| 184 | + u8 Revision; | |
| 185 | + u8 NumAuth; | |
| 186 | + u8 Authority[6]; | |
| 187 | + __le32 SubAuthorities[3]; | |
| 188 | +} __packed; | |
| 189 | + | |
| 190 | +struct owner_group_sids { | |
| 191 | + struct owner_sid owner; | |
| 192 | + struct owner_sid group; | |
| 193 | +} __packed; | |
| 179 | 194 | |
| 180 | 195 | /* |
| 181 | 196 | * Minimum security identifier can be one for system defined Users |
| @@ -623,7 +623,7 @@ cifs_show_options(struct seq_file *s, struct dentry *root) · 622 unmodified lines | ||
| 623 | 623 | seq_printf(s, ",actimeo=%lu", cifs_sb->actimeo / HZ); |
| 624 | 624 | |
| 625 | 625 | if (tcon->ses->chan_max > 1) |
| 626 | − seq_printf(s, ",multichannel,max_channel=%zu", | |
| 626 | + seq_printf(s, ",multichannel,max_channels=%zu", | |
| 627 | 627 | tcon->ses->chan_max); |
| 628 | 628 | |
| 629 | 629 | return 0; |
| @@ -2008,6 +2008,24 @@ extern struct smb_version_values smb302_values; · 2007 unmodified lines | ||
| 2008 | 2008 | extern struct smb_version_operations smb311_operations; |
| 2009 | 2009 | extern struct smb_version_values smb311_values; |
| 2010 | 2010 | |
| 2011 | +static inline char *get_security_type_str(enum securityEnum sectype) | |
| 2012 | +{ | |
| 2013 | + switch (sectype) { | |
| 2014 | + case RawNTLMSSP: | |
| 2015 | + return "RawNTLMSSP"; | |
| 2016 | + case Kerberos: | |
| 2017 | + return "Kerberos"; | |
| 2018 | + case NTLMv2: | |
| 2019 | + return "NTLMv2"; | |
| 2020 | + case NTLM: | |
| 2021 | + return "NTLM"; | |
| 2022 | + case LANMAN: | |
| 2023 | + return "LANMAN"; | |
| 2024 | + default: | |
| 2025 | + return "Unknown"; | |
| 2026 | + } | |
| 2027 | +} | |
| 2028 | + | |
| 2011 | 2029 | static inline bool is_smb1_server(struct TCP_Server_Info *server) |
| 2012 | 2030 | { |
| 2013 | 2031 | return strcmp(server->vals->version_string, SMB1_VERSION_STRING) == 0; |
| @@ -198,6 +198,8 @@ extern struct inode *cifs_iget(struct super_block *sb, · 197 unmodified lines | ||
| 198 | 198 | extern int cifs_get_inode_info(struct inode **inode, const char *full_path, |
| 199 | 199 | FILE_ALL_INFO *data, struct super_block *sb, |
| 200 | 200 | int xid, const struct cifs_fid *fid); |
| 201 | +extern int smb311_posix_get_inode_info(struct inode **pinode, const char *search_path, | |
| 202 | + struct super_block *sb, unsigned int xid); | |
| 201 | 203 | extern int cifs_get_inode_info_unix(struct inode **pinode, |
| 202 | 204 | const unsigned char *search_path, |
| 203 | 205 | struct super_block *sb, unsigned int xid); |
| @@ -220,6 +222,7 @@ extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *, · 16 unmodified lines | ||
| 220 | 222 | const char *, int); |
| 221 | 223 | extern unsigned int setup_authusers_ACE(struct cifs_ace *pace); |
| 222 | 224 | extern unsigned int setup_special_mode_ACE(struct cifs_ace *pace, __u64 nmode); |
| 225 | +extern unsigned int setup_special_user_owner_ACE(struct cifs_ace *pace); | |
| 223 | 226 | |
| 224 | 227 | extern void dequeue_mid(struct mid_q_entry *mid, bool malformed); |
| 225 | 228 | extern int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf, |
| @@ -411,6 +411,7 @@ cifs_create_get_file_info: · 410 unmodified lines | ||
| 411 | 411 | rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb, |
| 412 | 412 | xid); |
| 413 | 413 | else { |
| 414 | + /* TODO: Add support for calling POSIX query info here, but passing in fid */ | |
| 414 | 415 | rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb, |
| 415 | 416 | xid, fid); |
| 416 | 417 | if (newinode) { |
| @@ -700,7 +701,9 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, · 283 unmodified lines | ||
| 700 | 701 | cifs_dbg(FYI, "Full path: %s inode = 0x%p\n", |
| 701 | 702 | full_path, d_inode(direntry)); |
| 702 | 703 | |
| 703 | − if (pTcon->unix_ext) { | |
| 704 | + if (pTcon->posix_extensions) | |
| 705 | + rc = smb311_posix_get_inode_info(&newInode, full_path, parent_dir_inode->i_sb, xid); | |
| 706 | + else if (pTcon->unix_ext) { | |
| 704 | 707 | rc = cifs_get_inode_info_unix(&newInode, full_path, |
| 705 | 708 | parent_dir_inode->i_sb, xid); |
| 706 | 709 | } else { |
| @@ -243,6 +243,7 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, · 242 unmodified lines | ||
| 243 | 243 | if (rc) |
| 244 | 244 | goto out; |
| 245 | 245 | |
| 246 | + /* TODO: Add support for calling posix query info but with passing in fid */ | |
| 246 | 247 | if (tcon->unix_ext) |
| 247 | 248 | rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb, |
| 248 | 249 | xid); |
| @@ -800,7 +801,9 @@ reopen_success: · 551 unmodified lines | ||
| 800 | 801 | if (!is_interrupt_error(rc)) |
| 801 | 802 | mapping_set_error(inode->i_mapping, rc); |
| 802 | 803 | |
| 803 | − if (tcon->unix_ext) | |
| 804 | + if (tcon->posix_extensions) | |
| 805 | + rc = smb311_posix_get_inode_info(&inode, full_path, inode->i_sb, xid); | |
| 806 | + else if (tcon->unix_ext) | |
| 804 | 807 | rc = cifs_get_inode_info_unix(&inode, full_path, |
| 805 | 808 | inode->i_sb, xid); |
| 806 | 809 | else |
| @@ -96,6 +96,7 @@ void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) · 95 unmodified lines | ||
| 96 | 96 | { |
| 97 | 97 | struct TCP_Server_Info *server = tcon->ses->server; |
| 98 | 98 | char *sharename; |
| 99 | + struct cifs_fscache_super_auxdata auxdata; | |
| 99 | 100 | |
| 100 | 101 | sharename = extract_sharename(tcon->treeName); |
| 101 | 102 | if (IS_ERR(sharename)) { |
| @@ -104,11 +105,16 @@ void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) · 2 unmodified lines | ||
| 104 | 105 | return; |
| 105 | 106 | } |
| 106 | 107 | |
| 108 | + memset(&auxdata, 0, sizeof(auxdata)); | |
| 109 | + auxdata.resource_id = tcon->resource_id; | |
| 110 | + auxdata.vol_create_time = tcon->vol_create_time; | |
| 111 | + auxdata.vol_serial_number = tcon->vol_serial_number; | |
| 112 | + | |
| 107 | 113 | tcon->fscache = |
| 108 | 114 | fscache_acquire_cookie(server->fscache, |
| 109 | 115 | &cifs_fscache_super_index_def, |
| 110 | 116 | sharename, strlen(sharename), |
| 111 | − &tcon->resource_id, sizeof(tcon->resource_id), | |
| 117 | + &auxdata, sizeof(auxdata), | |
| 112 | 118 | tcon, 0, true); |
| 113 | 119 | kfree(sharename); |
| 114 | 120 | cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", |
| @@ -117,8 +123,15 @@ void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) · 2 unmodified lines | ||
| 117 | 123 | |
| 118 | 124 | void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon) |
| 119 | 125 | { |
| 126 | + struct cifs_fscache_super_auxdata auxdata; | |
| 127 | + | |
| 128 | + memset(&auxdata, 0, sizeof(auxdata)); | |
| 129 | + auxdata.resource_id = tcon->resource_id; | |
| 130 | + auxdata.vol_create_time = tcon->vol_create_time; | |
| 131 | + auxdata.vol_serial_number = tcon->vol_serial_number; | |
| 132 | + | |
| 120 | 133 | cifs_dbg(FYI, "%s: (0x%p)\n", __func__, tcon->fscache); |
| 121 | − fscache_relinquish_cookie(tcon->fscache, &tcon->resource_id, false); | |
| 134 | + fscache_relinquish_cookie(tcon->fscache, &auxdata, false); | |
| 122 | 135 | tcon->fscache = NULL; |
| 123 | 136 | } |
| 124 | 137 | |
| @@ -27,6 +27,15 @@ · 26 unmodified lines | ||
| 27 | 27 | |
| 28 | 28 | #ifdef CONFIG_CIFS_FSCACHE |
| 29 | 29 | |
| 30 | +/* | |
| 31 | + * Auxiliary data attached to CIFS superblock within the cache | |
| 32 | + */ | |
| 33 | +struct cifs_fscache_super_auxdata { | |
| 34 | + u64 resource_id; /* unique server resource id */ | |
| 35 | + __le64 vol_create_time; | |
| 36 | + u32 vol_serial_number; | |
| 37 | +} __packed; | |
| 38 | + | |
| 30 | 39 | /* |
| 31 | 40 | * Auxiliary data attached to CIFS inode within the cache |
| 32 | 41 | */ |
| @@ -32,6 +32,7 @@ · 31 unmodified lines | ||
| 32 | 32 | #include "cifspdu.h" |
| 33 | 33 | #include "cifsglob.h" |
| 34 | 34 | #include "cifsproto.h" |
| 35 | +#include "smb2proto.h" | |
| 35 | 36 | #include "cifs_debug.h" |
| 36 | 37 | #include "cifs_fs_sb.h" |
| 37 | 38 | #include "cifs_unicode.h" |
| @@ -595,6 +596,62 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, · 557 unmodified lines | ||
| 595 | 596 | #endif |
| 596 | 597 | } |
| 597 | 598 | |
| 599 | +/* Fill a cifs_fattr struct with info from POSIX info struct */ | |
| 600 | +static void | |
| 601 | +smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct smb311_posix_qinfo *info, | |
| 602 | + struct super_block *sb, bool adjust_tz, bool symlink) | |
| 603 | +{ | |
| 604 | + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | |
| 605 | + struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); | |
| 606 | + | |
| 607 | + memset(fattr, 0, sizeof(*fattr)); | |
| 608 | + | |
| 609 | + /* no fattr->flags to set */ | |
| 610 | + fattr->cf_cifsattrs = le32_to_cpu(info->DosAttributes); | |
| 611 | + fattr->cf_uniqueid = le64_to_cpu(info->Inode); | |
| 612 | + | |
| 613 | + if (info->LastAccessTime) | |
| 614 | + fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); | |
| 615 | + else | |
| 616 | + ktime_get_coarse_real_ts64(&fattr->cf_atime); | |
| 617 | + | |
| 618 | + fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); | |
| 619 | + fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); | |
| 620 | + | |
| 621 | + if (adjust_tz) { | |
| 622 | + fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj; | |
| 623 | + fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj; | |
| 624 | + } | |
| 625 | + | |
| 626 | + fattr->cf_eof = le64_to_cpu(info->EndOfFile); | |
| 627 | + fattr->cf_bytes = le64_to_cpu(info->AllocationSize); | |
| 628 | + fattr->cf_createtime = le64_to_cpu(info->CreationTime); | |
| 629 | + | |
| 630 | + fattr->cf_nlink = le32_to_cpu(info->HardLinks); | |
| 631 | + fattr->cf_mode = (umode_t) le32_to_cpu(info->Mode); | |
| 632 | + /* The srv fs device id is overridden on network mount so setting rdev isn't needed here */ | |
| 633 | + /* fattr->cf_rdev = le32_to_cpu(info->DeviceId); */ | |
| 634 | + | |
| 635 | + if (symlink) { | |
| 636 | + fattr->cf_mode |= S_IFLNK; | |
| 637 | + fattr->cf_dtype = DT_LNK; | |
| 638 | + } else if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { | |
| 639 | + fattr->cf_mode |= S_IFDIR; | |
| 640 | + fattr->cf_dtype = DT_DIR; | |
| 641 | + } else { /* file */ | |
| 642 | + fattr->cf_mode |= S_IFREG; | |
| 643 | + fattr->cf_dtype = DT_REG; | |
| 644 | + } | |
| 645 | + /* else if reparse point ... TODO: add support for FIFO and blk dev; special file types */ | |
| 646 | + | |
| 647 | + fattr->cf_uid = cifs_sb->mnt_uid; /* TODO: map uid and gid from SID */ | |
| 648 | + fattr->cf_gid = cifs_sb->mnt_gid; | |
| 649 | + | |
| 650 | + cifs_dbg(FYI, "POSIX query info: mode 0x%x uniqueid 0x%llx nlink %d\n", | |
| 651 | + fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink); | |
| 652 | +} | |
| 653 | + | |
| 654 | + | |
| 598 | 655 | /* Fill a cifs_fattr struct with info from FILE_ALL_INFO */ |
| 599 | 656 | static void |
| 600 | 657 | cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, |
| @@ -1023,6 +1080,121 @@ out: · 422 unmodified lines | ||
| 1023 | 1080 | return rc; |
| 1024 | 1081 | } |
| 1025 | 1082 | |
| 1083 | +int | |
| 1084 | +smb311_posix_get_inode_info(struct inode **inode, | |
| 1085 | + const char *full_path, | |
| 1086 | + struct super_block *sb, unsigned int xid) | |
| 1087 | +{ | |
| 1088 | + struct cifs_tcon *tcon; | |
| 1089 | + struct TCP_Server_Info *server; | |
| 1090 | + struct tcon_link *tlink; | |
| 1091 | + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | |
| 1092 | + bool adjust_tz = false; | |
| 1093 | + struct cifs_fattr fattr = {0}; | |
| 1094 | + bool symlink = false; | |
| 1095 | + struct smb311_posix_qinfo *data = NULL; | |
| 1096 | + int rc = 0; | |
| 1097 | + int tmprc = 0; | |
| 1098 | + | |
| 1099 | + tlink = cifs_sb_tlink(cifs_sb); | |
| 1100 | + if (IS_ERR(tlink)) | |
| 1101 | + return PTR_ERR(tlink); | |
| 1102 | + tcon = tlink_tcon(tlink); | |
| 1103 | + server = tcon->ses->server; | |
| 1104 | + | |
| 1105 | + /* | |
| 1106 | + * 1. Fetch file metadata | |
| 1107 | + */ | |
| 1108 | + | |
| 1109 | + if (is_inode_cache_good(*inode)) { | |
| 1110 | + cifs_dbg(FYI, "No need to revalidate cached inode sizes\n"); | |
| 1111 | + goto out; | |
| 1112 | + } | |
| 1113 | + data = kmalloc(sizeof(struct smb311_posix_qinfo), GFP_KERNEL); | |
| 1114 | + if (!data) { | |
| 1115 | + rc = -ENOMEM; | |
| 1116 | + goto out; | |
| 1117 | + } | |
| 1118 | + | |
| 1119 | + rc = smb311_posix_query_path_info(xid, tcon, cifs_sb, | |
| 1120 | + full_path, data, | |
| 1121 | + &adjust_tz, &symlink); | |
| 1122 | + | |
| 1123 | + /* | |
| 1124 | + * 2. Convert it to internal cifs metadata (fattr) | |
| 1125 | + */ | |
| 1126 | + | |
| 1127 | + switch (rc) { | |
| 1128 | + case 0: | |
| 1129 | + smb311_posix_info_to_fattr(&fattr, data, sb, adjust_tz, symlink); | |
| 1130 | + break; | |
| 1131 | + case -EREMOTE: | |
| 1132 | + /* DFS link, no metadata available on this server */ | |
| 1133 | + cifs_create_dfs_fattr(&fattr, sb); | |
| 1134 | + rc = 0; | |
| 1135 | + break; | |
| 1136 | + case -EACCES: | |
| 1137 | + /* | |
| 1138 | + * For SMB2 and later the backup intent flag | |
| 1139 | + * is already sent if needed on open and there | |
| 1140 | + * is no path based FindFirst operation to use | |
| 1141 | + * to retry with so nothing we can do, bail out | |
| 1142 | + */ | |
| 1143 | + goto out; | |
| 1144 | + default: | |
| 1145 | + cifs_dbg(FYI, "%s: unhandled err rc %d\n", __func__, rc); | |
| 1146 | + goto out; | |
| 1147 | + } | |
| 1148 | + | |
| 1149 | + | |
| 1150 | + /* | |
| 1151 | + * 3. Tweak fattr based on mount options | |
| 1152 | + */ | |
| 1153 | + | |
| 1154 | + /* check for Minshall+French symlinks */ | |
| 1155 | + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { | |
| 1156 | + tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr, | |
| 1157 | + full_path); | |
| 1158 | + if (tmprc) | |
| 1159 | + cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc); | |
| 1160 | + } | |
| 1161 | + | |
| 1162 | + /* | |
| 1163 | + * 4. Update inode with final fattr data | |
| 1164 | + */ | |
| 1165 | + | |
| 1166 | + if (!*inode) { | |
| 1167 | + *inode = cifs_iget(sb, &fattr); | |
| 1168 | + if (!*inode) | |
| 1169 | + rc = -ENOMEM; | |
| 1170 | + } else { | |
| 1171 | + /* we already have inode, update it */ | |
| 1172 | + | |
| 1173 | + /* if uniqueid is different, return error */ | |
| 1174 | + if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM && | |
| 1175 | + CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) { | |
| 1176 | + CIFS_I(*inode)->time = 0; /* force reval */ | |
| 1177 | + rc = -ESTALE; | |
| 1178 | + goto out; | |
| 1179 | + } | |
| 1180 | + | |
| 1181 | + /* if filetype is different, return error */ | |
| 1182 | + if (unlikely(((*inode)->i_mode & S_IFMT) != | |
| 1183 | + (fattr.cf_mode & S_IFMT))) { | |
| 1184 | + CIFS_I(*inode)->time = 0; /* force reval */ | |
| 1185 | + rc = -ESTALE; | |
| 1186 | + goto out; | |
| 1187 | + } | |
| 1188 | + | |
| 1189 | + cifs_fattr_to_inode(*inode, &fattr); | |
| 1190 | + } | |
| 1191 | +out: | |
| 1192 | + cifs_put_tlink(tlink); | |
| 1193 | + kfree(data); | |
| 1194 | + return rc; | |
| 1195 | +} | |
| 1196 | + | |
| 1197 | + | |
| 1026 | 1198 | static const struct inode_operations cifs_ipc_inode_ops = { |
| 1027 | 1199 | .lookup = cifs_lookup, |
| 1028 | 1200 | }; |
| @@ -1161,7 +1333,10 @@ struct inode *cifs_root_iget(struct super_block *sb) · 132 unmodified lines | ||
| 1161 | 1333 | } |
| 1162 | 1334 | |
| 1163 | 1335 | convert_delimiter(path, CIFS_DIR_SEP(cifs_sb)); |
| 1164 | − rc = cifs_get_inode_info(&inode, path, NULL, sb, xid, NULL); | |
| 1336 | + if (tcon->posix_extensions) | |
| 1337 | + rc = smb311_posix_get_inode_info(&inode, path, sb, xid); | |
| 1338 | + else | |
| 1339 | + rc = cifs_get_inode_info(&inode, path, NULL, sb, xid, NULL); | |
| 1165 | 1340 | |
| 1166 | 1341 | iget_no_retry: |
| 1167 | 1342 | if (!inode) { |
| @@ -1517,7 +1692,9 @@ cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode, · 349 unmodified lines | ||
| 1517 | 1692 | int rc = 0; |
| 1518 | 1693 | struct inode *inode = NULL; |
| 1519 | 1694 | |
| 1520 | − if (tcon->unix_ext) | |
| 1695 | + if (tcon->posix_extensions) | |
| 1696 | + rc = smb311_posix_get_inode_info(&inode, full_path, parent->i_sb, xid); | |
| 1697 | + else if (tcon->unix_ext) | |
| 1521 | 1698 | rc = cifs_get_inode_info_unix(&inode, full_path, parent->i_sb, |
| 1522 | 1699 | xid); |
| 1523 | 1700 | else |
| @@ -2114,7 +2291,9 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry) · 590 unmodified lines | ||
| 2114 | 2291 | dentry, cifs_get_time(dentry), jiffies); |
| 2115 | 2292 | |
| 2116 | 2293 | again: |
| 2117 | − if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) | |
| 2294 | + if (cifs_sb_master_tcon(CIFS_SB(sb))->posix_extensions) | |
| 2295 | + rc = smb311_posix_get_inode_info(&inode, full_path, sb, xid); | |
| 2296 | + else if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) | |
| 2118 | 2297 | rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); |
| 2119 | 2298 | else |
| 2120 | 2299 | rc = cifs_get_inode_info(&inode, full_path, NULL, sb, |
| @@ -701,7 +701,9 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) · 700 unmodified lines | ||
| 701 | 701 | cifs_sb_target->local_nls); */ |
| 702 | 702 | |
| 703 | 703 | if (rc == 0) { |
| 704 | − if (pTcon->unix_ext) | |
| 704 | + if (pTcon->posix_extensions) | |
| 705 | + rc = smb311_posix_get_inode_info(&newinode, full_path, inode->i_sb, xid); | |
| 706 | + else if (pTcon->unix_ext) | |
| 705 | 707 | rc = cifs_get_inode_info_unix(&newinode, full_path, |
| 706 | 708 | inode->i_sb, xid); |
| 707 | 709 | else |
| @@ -45,6 +45,7 @@ · 44 unmodified lines | ||
| 45 | 45 | #define SMB2_OP_HARDLINK 8 |
| 46 | 46 | #define SMB2_OP_SET_EOF 9 |
| 47 | 47 | #define SMB2_OP_RMDIR 10 |
| 48 | +#define SMB2_OP_POSIX_QUERY_INFO 11 | |
| 48 | 49 | |
| 49 | 50 | /* Used when constructing chained read requests. */ |
| 50 | 51 | #define CHAINED_REQUEST 1 |
| @@ -166,6 +166,40 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, · 165 unmodified lines | ||
| 166 | 166 | trace_smb3_query_info_compound_enter(xid, ses->Suid, tcon->tid, |
| 167 | 167 | full_path); |
| 168 | 168 | break; |
| 169 | + case SMB2_OP_POSIX_QUERY_INFO: | |
| 170 | + rqst[num_rqst].rq_iov = &vars->qi_iov[0]; | |
| 171 | + rqst[num_rqst].rq_nvec = 1; | |
| 172 | + | |
| 173 | + if (cfile) | |
| 174 | + rc = SMB2_query_info_init(tcon, server, | |
| 175 | + &rqst[num_rqst], | |
| 176 | + cfile->fid.persistent_fid, | |
| 177 | + cfile->fid.volatile_fid, | |
| 178 | + SMB_FIND_FILE_POSIX_INFO, | |
| 179 | + SMB2_O_INFO_FILE, 0, | |
| 180 | + /* TBD: fix following to allow for longer SIDs */ | |
| 181 | + sizeof(struct smb311_posix_qinfo *) + (PATH_MAX * 2) + | |
| 182 | + (sizeof(struct cifs_sid) * 2), 0, NULL); | |
| 183 | + else { | |
| 184 | + rc = SMB2_query_info_init(tcon, server, | |
| 185 | + &rqst[num_rqst], | |
| 186 | + COMPOUND_FID, | |
| 187 | + COMPOUND_FID, | |
| 188 | + SMB_FIND_FILE_POSIX_INFO, | |
| 189 | + SMB2_O_INFO_FILE, 0, | |
| 190 | + sizeof(struct smb311_posix_qinfo *) + (PATH_MAX * 2) + | |
| 191 | + (sizeof(struct cifs_sid) * 2), 0, NULL); | |
| 192 | + if (!rc) { | |
| 193 | + smb2_set_next_command(tcon, &rqst[num_rqst]); | |
| 194 | + smb2_set_related(&rqst[num_rqst]); | |
| 195 | + } | |
| 196 | + } | |
| 197 | + | |
| 198 | + if (rc) | |
| 199 | + goto finished; | |
| 200 | + num_rqst++; | |
| 201 | + trace_smb3_posix_query_info_compound_enter(xid, ses->Suid, tcon->tid, full_path); | |
| 202 | + break; | |
| 169 | 203 | case SMB2_OP_DELETE: |
| 170 | 204 | trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, full_path); |
| 171 | 205 | break; |
| @@ -379,6 +413,24 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, · 207 unmodified lines | ||
| 379 | 413 | trace_smb3_query_info_compound_done(xid, ses->Suid, |
| 380 | 414 | tcon->tid); |
| 381 | 415 | break; |
| 416 | + case SMB2_OP_POSIX_QUERY_INFO: | |
| 417 | + if (rc == 0) { | |
| 418 | + qi_rsp = (struct smb2_query_info_rsp *) | |
| 419 | + rsp_iov[1].iov_base; | |
| 420 | + rc = smb2_validate_and_copy_iov( | |
| 421 | + le16_to_cpu(qi_rsp->OutputBufferOffset), | |
| 422 | + le32_to_cpu(qi_rsp->OutputBufferLength), | |
| 423 | + &rsp_iov[1], sizeof(struct smb311_posix_qinfo) /* add SIDs */, ptr); | |
| 424 | + } | |
| 425 | + if (rqst[1].rq_iov) | |
| 426 | + SMB2_query_info_free(&rqst[1]); | |
| 427 | + if (rqst[2].rq_iov) | |
| 428 | + SMB2_close_free(&rqst[2]); | |
| 429 | + if (rc) | |
| 430 | + trace_smb3_posix_query_info_compound_err(xid, ses->Suid, tcon->tid, rc); | |
| 431 | + else | |
| 432 | + trace_smb3_posix_query_info_compound_done(xid, ses->Suid, tcon->tid); | |
| 433 | + break; | |
| 382 | 434 | case SMB2_OP_DELETE: |
| 383 | 435 | if (rc) |
| 384 | 436 | trace_smb3_delete_err(xid, ses->Suid, tcon->tid, rc); |
| @@ -512,6 +564,59 @@ out: · 127 unmodified lines | ||
| 512 | 564 | return rc; |
| 513 | 565 | } |
| 514 | 566 | |
| 567 | + | |
| 568 | +int | |
| 569 | +smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, | |
| 570 | + struct cifs_sb_info *cifs_sb, const char *full_path, | |
| 571 | + struct smb311_posix_qinfo *data, bool *adjust_tz, bool *symlink) | |
| 572 | +{ | |
| 573 | + int rc; | |
| 574 | + __u32 create_options = 0; | |
| 575 | + struct cifsFileInfo *cfile; | |
| 576 | + struct smb311_posix_qinfo *smb2_data; | |
| 577 | + | |
| 578 | + *adjust_tz = false; | |
| 579 | + *symlink = false; | |
| 580 | + | |
| 581 | + /* BB TODO: Make struct larger when add support for parsing owner SIDs */ | |
| 582 | + smb2_data = kzalloc(sizeof(struct smb311_posix_qinfo), | |
| 583 | + GFP_KERNEL); | |
| 584 | + if (smb2_data == NULL) | |
| 585 | + return -ENOMEM; | |
| 586 | + | |
| 587 | + /* | |
| 588 | + * BB TODO: Add support for using the cached root handle. | |
| 589 | + * Create SMB2_query_posix_info worker function to do non-compounded query | |
| 590 | + * when we already have an open file handle for this. For now this is fast enough | |
| 591 | + * (always using the compounded version). | |
| 592 | + */ | |
| 593 | + | |
| 594 | + cifs_get_readable_path(tcon, full_path, &cfile); | |
| 595 | + rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, | |
| 596 | + FILE_READ_ATTRIBUTES, FILE_OPEN, create_options, | |
| 597 | + ACL_NO_MODE, smb2_data, SMB2_OP_POSIX_QUERY_INFO, cfile); | |
| 598 | + if (rc == -EOPNOTSUPP) { | |
| 599 | + /* BB TODO: When support for special files added to Samba re-verify this path */ | |
| 600 | + *symlink = true; | |
| 601 | + create_options |= OPEN_REPARSE_POINT; | |
| 602 | + | |
| 603 | + /* Failed on a symbolic link - query a reparse point info */ | |
| 604 | + rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, | |
| 605 | + FILE_READ_ATTRIBUTES, FILE_OPEN, | |
| 606 | + create_options, ACL_NO_MODE, | |
| 607 | + smb2_data, SMB2_OP_POSIX_QUERY_INFO, NULL); | |
| 608 | + } | |
| 609 | + if (rc) | |
| 610 | + goto out; | |
| 611 | + | |
| 612 | + /* TODO: will need to allow for the 2 SIDs when add support for getting owner UID/GID */ | |
| 613 | + memcpy(data, smb2_data, sizeof(struct smb311_posix_qinfo)); | |
| 614 | + | |
| 615 | +out: | |
| 616 | + kfree(smb2_data); | |
| 617 | + return rc; | |
| 618 | +} | |
| 619 | + | |
| 515 | 620 | int |
| 516 | 621 | smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode, |
| 517 | 622 | struct cifs_tcon *tcon, const char *name, |
| @@ -2317,28 +2317,75 @@ add_twarp_context(struct kvec *iov, unsigned int *num_iovec, __u64 timewarp) · 2316 unmodified lines | ||
| 2317 | 2317 | return 0; |
| 2318 | 2318 | } |
| 2319 | 2319 | |
| 2320 | +/* See See http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx */ | |
| 2321 | +static void setup_owner_group_sids(char *buf) | |
| 2322 | +{ | |
| 2323 | + struct owner_group_sids *sids = (struct owner_group_sids *)buf; | |
| 2324 | + | |
| 2325 | + /* Populate the user ownership fields S-1-5-88-1 */ | |
| 2326 | + sids->owner.Revision = 1; | |
| 2327 | + sids->owner.NumAuth = 3; | |
| 2328 | + sids->owner.Authority[5] = 5; | |
| 2329 | + sids->owner.SubAuthorities[0] = cpu_to_le32(88); | |
| 2330 | + sids->owner.SubAuthorities[1] = cpu_to_le32(1); | |
| 2331 | + sids->owner.SubAuthorities[2] = cpu_to_le32(current_fsuid().val); | |
| 2332 | + | |
| 2333 | + /* Populate the group ownership fields S-1-5-88-2 */ | |
| 2334 | + sids->group.Revision = 1; | |
| 2335 | + sids->group.NumAuth = 3; | |
| 2336 | + sids->group.Authority[5] = 5; | |
| 2337 | + sids->group.SubAuthorities[0] = cpu_to_le32(88); | |
| 2338 | + sids->group.SubAuthorities[1] = cpu_to_le32(2); | |
| 2339 | + sids->group.SubAuthorities[2] = cpu_to_le32(current_fsgid().val); | |
| 2340 | + | |
| 2341 | + cifs_dbg(FYI, "owner S-1-5-88-1-%d, group S-1-5-88-2-%d\n", current_fsuid().val, current_fsgid().val); | |
| 2342 | +} | |
| 2343 | + | |
| 2320 | 2344 | /* See MS-SMB2 2.2.13.2.2 and MS-DTYP 2.4.6 */ |
| 2321 | 2345 | static struct crt_sd_ctxt * |
| 2322 | −create_sd_buf(umode_t mode, unsigned int *len) | |
| 2346 | +create_sd_buf(umode_t mode, bool set_owner, unsigned int *len) | |
| 2323 | 2347 | { |
| 2324 | 2348 | struct crt_sd_ctxt *buf; |
| 2325 | 2349 | struct cifs_ace *pace; |
| 2326 | 2350 | unsigned int sdlen, acelen; |
| 2351 | + unsigned int owner_offset = 0; | |
| 2352 | + unsigned int group_offset = 0; | |
| 2353 | + | |
| 2354 | + *len = roundup(sizeof(struct crt_sd_ctxt) + (sizeof(struct cifs_ace) * 2), 8); | |
| 2355 | + | |
| 2356 | + if (set_owner) { | |
| 2357 | + /* offset fields are from beginning of security descriptor not of create context */ | |
| 2358 | + owner_offset = sizeof(struct smb3_acl) + (sizeof(struct cifs_ace) * 2); | |
| 2359 | + | |
| 2360 | + /* sizeof(struct owner_group_sids) is already multiple of 8 so no need to round */ | |
| 2361 | + *len += sizeof(struct owner_group_sids); | |
| 2362 | + } | |
| 2327 | 2363 | |
| 2328 | − *len = roundup(sizeof(struct crt_sd_ctxt) + sizeof(struct cifs_ace) * 2, | |
| 2329 | − 8); | |
| 2330 | 2364 | buf = kzalloc(*len, GFP_KERNEL); |
| 2331 | 2365 | if (buf == NULL) |
| 2332 | 2366 | return buf; |
| 2333 | 2367 | |
| 2368 | + if (set_owner) { | |
| 2369 | + buf->sd.OffsetOwner = cpu_to_le32(owner_offset); | |
| 2370 | + group_offset = owner_offset + sizeof(struct owner_sid); | |
| 2371 | + buf->sd.OffsetGroup = cpu_to_le32(group_offset); | |
| 2372 | + } else { | |
| 2373 | + buf->sd.OffsetOwner = 0; | |
| 2374 | + buf->sd.OffsetGroup = 0; | |
| 2375 | + } | |
| 2376 | + | |
| 2334 | 2377 | sdlen = sizeof(struct smb3_sd) + sizeof(struct smb3_acl) + |
| 2335 | 2378 | 2 * sizeof(struct cifs_ace); |
| 2379 | + if (set_owner) { | |
| 2380 | + sdlen += sizeof(struct owner_group_sids); | |
| 2381 | + setup_owner_group_sids(owner_offset + sizeof(struct create_context) + 8 /* name */ | |
| 2382 | + + (char *)buf); | |
| 2383 | + } | |
| 2336 | 2384 | |
| 2337 | 2385 | buf->ccontext.DataOffset = cpu_to_le16(offsetof |
| 2338 | 2386 | (struct crt_sd_ctxt, sd)); |
| 2339 | 2387 | buf->ccontext.DataLength = cpu_to_le32(sdlen); |
| 2340 | − buf->ccontext.NameOffset = cpu_to_le16(offsetof | |
| 2341 | − (struct crt_sd_ctxt, Name)); | |
| 2388 | + buf->ccontext.NameOffset = cpu_to_le16(offsetof(struct crt_sd_ctxt, Name)); | |
| 2342 | 2389 | buf->ccontext.NameLength = cpu_to_le16(4); |
| 2343 | 2390 | /* SMB2_CREATE_SD_BUFFER_TOKEN is "SecD" */ |
| 2344 | 2391 | buf->Name[0] = 'S'; |
| @@ -2359,23 +2406,34 @@ create_sd_buf(umode_t mode, unsigned int *len) · 14 unmodified lines | ||
| 2359 | 2406 | /* create one ACE to hold the mode embedded in reserved special SID */ |
| 2360 | 2407 | pace = (struct cifs_ace *)(sizeof(struct crt_sd_ctxt) + (char *)buf); |
| 2361 | 2408 | acelen = setup_special_mode_ACE(pace, (__u64)mode); |
| 2409 | + | |
| 2410 | + if (set_owner) { | |
| 2411 | + /* we do not need to reallocate buffer to add the two more ACEs. plenty of space */ | |
| 2412 | + pace = (struct cifs_ace *)(acelen + (sizeof(struct crt_sd_ctxt) + (char *)buf)); | |
| 2413 | + acelen += setup_special_user_owner_ACE(pace); | |
| 2414 | + /* it does not appear necessary to add an ACE for the NFS group SID */ | |
| 2415 | + buf->acl.AceCount = cpu_to_le16(3); | |
| 2416 | + } else | |
| 2417 | + buf->acl.AceCount = cpu_to_le16(2); | |
| 2418 | + | |
| 2362 | 2419 | /* and one more ACE to allow access for authenticated users */ |
| 2363 | 2420 | pace = (struct cifs_ace *)(acelen + (sizeof(struct crt_sd_ctxt) + |
| 2364 | 2421 | (char *)buf)); |
| 2365 | 2422 | acelen += setup_authusers_ACE(pace); |
| 2423 | + | |
| 2366 | 2424 | buf->acl.AclSize = cpu_to_le16(sizeof(struct cifs_acl) + acelen); |
| 2367 | − buf->acl.AceCount = cpu_to_le16(2); | |
| 2425 | + | |
| 2368 | 2426 | return buf; |
| 2369 | 2427 | } |
| 2370 | 2428 | |
| 2371 | 2429 | static int |
| 2372 | −add_sd_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode) | |
| 2430 | +add_sd_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode, bool set_owner) | |
| 2373 | 2431 | { |
| 2374 | 2432 | struct smb2_create_req *req = iov[0].iov_base; |
| 2375 | 2433 | unsigned int num = *num_iovec; |
| 2376 | 2434 | unsigned int len = 0; |
| 2377 | 2435 | |
| 2378 | − iov[num].iov_base = create_sd_buf(mode, &len); | |
| 2436 | + iov[num].iov_base = create_sd_buf(mode, set_owner, &len); | |
| 2379 | 2437 | if (iov[num].iov_base == NULL) |
| 2380 | 2438 | return -ENOMEM; |
| 2381 | 2439 | iov[num].iov_len = len; |
| @@ -2764,21 +2822,35 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server, · 382 unmodified lines | ||
| 2764 | 2822 | return rc; |
| 2765 | 2823 | } |
| 2766 | 2824 | |
| 2767 | − if ((oparms->disposition != FILE_OPEN) && | |
| 2768 | − (oparms->cifs_sb) && | |
| 2769 | − (oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) && | |
| 2770 | − (oparms->mode != ACL_NO_MODE)) { | |
| 2771 | − if (n_iov > 2) { | |
| 2772 | − struct create_context *ccontext = | |
| 2773 | − (struct create_context *)iov[n_iov-1].iov_base; | |
| 2774 | − ccontext->Next = | |
| 2775 | − cpu_to_le32(iov[n_iov-1].iov_len); | |
| 2825 | + if ((oparms->disposition != FILE_OPEN) && (oparms->cifs_sb)) { | |
| 2826 | + bool set_mode; | |
| 2827 | + bool set_owner; | |
| 2828 | + | |
| 2829 | + if ((oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) && | |
| 2830 | + (oparms->mode != ACL_NO_MODE)) | |
| 2831 | + set_mode = true; | |
| 2832 | + else { | |
| 2833 | + set_mode = false; | |
| 2834 | + oparms->mode = ACL_NO_MODE; | |
| 2776 | 2835 | } |
| 2777 | 2836 | |
| 2778 | − cifs_dbg(FYI, "add sd with mode 0x%x\n", oparms->mode); | |
| 2779 | − rc = add_sd_context(iov, &n_iov, oparms->mode); | |
| 2780 | − if (rc) | |
| 2781 | − return rc; | |
| 2837 | + if (oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) | |
| 2838 | + set_owner = true; | |
| 2839 | + else | |
| 2840 | + set_owner = false; | |
| 2841 | + | |
| 2842 | + if (set_owner | set_mode) { | |
| 2843 | + if (n_iov > 2) { | |
| 2844 | + struct create_context *ccontext = | |
| 2845 | + (struct create_context *)iov[n_iov-1].iov_base; | |
| 2846 | + ccontext->Next = cpu_to_le32(iov[n_iov-1].iov_len); | |
| 2847 | + } | |
| 2848 | + | |
| 2849 | + cifs_dbg(FYI, "add sd with mode 0x%x\n", oparms->mode); | |
| 2850 | + rc = add_sd_context(iov, &n_iov, oparms->mode, set_owner); | |
| 2851 | + if (rc) | |
| 2852 | + return rc; | |
| 2853 | + } | |
| 2782 | 2854 | } |
| 2783 | 2855 | |
| 2784 | 2856 | if (n_iov > 2) { |
| @@ -2973,7 +3045,9 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server, · 188 unmodified lines | ||
| 2973 | 3045 | * response size smaller. |
| 2974 | 3046 | */ |
| 2975 | 3047 | req->MaxOutputResponse = cpu_to_le32(max_response_size); |
| 2976 | − req->sync_hdr.CreditCharge = cpu_to_le16(DIV_ROUND_UP(max_response_size, SMB2_MAX_BUFFER_SIZE)); | |
| 3048 | + req->sync_hdr.CreditCharge = | |
| 3049 | + cpu_to_le16(DIV_ROUND_UP(max(indatalen, max_response_size), | |
| 3050 | + SMB2_MAX_BUFFER_SIZE)); | |
| 2977 | 3051 | if (is_fsctl) |
| 2978 | 3052 | req->Flags = cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL); |
| 2979 | 3053 | else |
| @@ -3456,6 +3530,19 @@ int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon, · 476 unmodified lines | ||
| 3456 | 3530 | NULL); |
| 3457 | 3531 | } |
| 3458 | 3532 | |
| 3533 | +int | |
| 3534 | +SMB311_posix_query_info(const unsigned int xid, struct cifs_tcon *tcon, | |
| 3535 | + u64 persistent_fid, u64 volatile_fid, struct smb311_posix_qinfo *data, u32 *plen) | |
| 3536 | +{ | |
| 3537 | + size_t output_len = sizeof(struct smb311_posix_qinfo *) + | |
| 3538 | + (sizeof(struct cifs_sid) * 2) + (PATH_MAX * 2); | |
| 3539 | + *plen = 0; | |
| 3540 | + | |
| 3541 | + return query_info(xid, tcon, persistent_fid, volatile_fid, | |
| 3542 | + SMB_FIND_FILE_POSIX_INFO, SMB2_O_INFO_FILE, 0, | |
| 3543 | + output_len, sizeof(struct smb311_posix_qinfo), (void **)&data, plen); | |
| 3544 | +} | |
| 3545 | + | |
| 3459 | 3546 | int |
| 3460 | 3547 | SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon, |
| 3461 | 3548 | u64 persistent_fid, u64 volatile_fid, |
| @@ -1653,7 +1653,7 @@ struct create_posix_rsp { · 1652 unmodified lines | ||
| 1653 | 1653 | } __packed; |
| 1654 | 1654 | |
| 1655 | 1655 | /* |
| 1656 | − * SMB2-only POSIX info level | |
| 1656 | + * SMB2-only POSIX info level for query dir | |
| 1657 | 1657 | * |
| 1658 | 1658 | * See posix_info_sid_size(), posix_info_extra_size() and |
| 1659 | 1659 | * posix_info_parse() to help with the handling of this struct. |
| @@ -1683,6 +1683,31 @@ struct smb2_posix_info { · 23 unmodified lines | ||
| 1683 | 1683 | */ |
| 1684 | 1684 | } __packed; |
| 1685 | 1685 | |
| 1686 | +/* Level 100 query info */ | |
| 1687 | +struct smb311_posix_qinfo { | |
| 1688 | + __le64 CreationTime; | |
| 1689 | + __le64 LastAccessTime; | |
| 1690 | + __le64 LastWriteTime; | |
| 1691 | + __le64 ChangeTime; | |
| 1692 | + __le64 EndOfFile; | |
| 1693 | + __le64 AllocationSize; | |
| 1694 | + __le32 DosAttributes; | |
| 1695 | + __le64 Inode; | |
| 1696 | + __le32 DeviceId; | |
| 1697 | + __le32 Zero; | |
| 1698 | + /* beginning of POSIX Create Context Response */ | |
| 1699 | + __le32 HardLinks; | |
| 1700 | + __le32 ReparseTag; | |
| 1701 | + __le32 Mode; | |
| 1702 | + u8 Sids[]; | |
| 1703 | + /* | |
| 1704 | + * var sized owner SID | |
| 1705 | + * var sized group SID | |
| 1706 | + * le32 filenamelength | |
| 1707 | + * u8 filename[] | |
| 1708 | + */ | |
| 1709 | +} __packed; | |
| 1710 | + | |
| 1686 | 1711 | /* |
| 1687 | 1712 | * Parsed version of the above struct. Allows direct access to the |
| 1688 | 1713 | * variable length fields |
| @@ -182,6 +182,8 @@ extern int SMB2_flush_init(const unsigned int xid, struct smb_rqst *rqst, · 181 unmodified lines | ||
| 182 | 182 | struct TCP_Server_Info *server, |
| 183 | 183 | u64 persistent_file_id, u64 volatile_file_id); |
| 184 | 184 | extern void SMB2_flush_free(struct smb_rqst *rqst); |
| 185 | +extern int SMB311_posix_query_info(const unsigned int xid, struct cifs_tcon *tcon, | |
| 186 | + u64 persistent_fid, u64 volatile_fid, struct smb311_posix_qinfo *data, u32 *plen); | |
| 185 | 187 | extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon, |
| 186 | 188 | u64 persistent_file_id, u64 volatile_file_id, |
| 187 | 189 | struct smb2_file_all_info *data); |
| @@ -289,6 +291,10 @@ extern int smb2_query_info_compound(const unsigned int xid, · 101 unmodified lines | ||
| 289 | 291 | u32 class, u32 type, u32 output_len, |
| 290 | 292 | struct kvec *rsp, int *buftype, |
| 291 | 293 | struct cifs_sb_info *cifs_sb); |
| 294 | +/* query path info from the server using SMB311 POSIX extensions*/ | |
| 295 | +extern int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, | |
| 296 | + struct cifs_sb_info *sb, const char *path, struct smb311_posix_qinfo *qinf, | |
| 297 | + bool *adjust_tx, bool *symlink); | |
| 292 | 298 | int posix_info_parse(const void *beg, const void *end, |
| 293 | 299 | struct smb2_posix_info_parsed *out); |
| 294 | 300 | int posix_info_sid_size(const void *beg, const void *end); |
| @@ -318,6 +318,7 @@ DEFINE_EVENT(smb3_inf_compound_enter_class, smb3_##name, \ · 317 unmodified lines | ||
| 318 | 318 | TP_ARGS(xid, tid, sesid, full_path)) |
| 319 | 319 | |
| 320 | 320 | DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(query_info_compound_enter); |
| 321 | +DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(posix_query_info_compound_enter); | |
| 321 | 322 | DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(hardlink_enter); |
| 322 | 323 | DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(rename_enter); |
| 323 | 324 | DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(rmdir_enter); |
| @@ -354,6 +355,7 @@ DEFINE_EVENT(smb3_inf_compound_done_class, smb3_##name, \ · 30 unmodified lines | ||
| 354 | 355 | TP_ARGS(xid, tid, sesid)) |
| 355 | 356 | |
| 356 | 357 | DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(query_info_compound_done); |
| 358 | +DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(posix_query_info_compound_done); | |
| 357 | 359 | DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(hardlink_done); |
| 358 | 360 | DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(rename_done); |
| 359 | 361 | DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(rmdir_done); |
| @@ -395,6 +397,7 @@ DEFINE_EVENT(smb3_inf_compound_err_class, smb3_##name, \ · 35 unmodified lines | ||
| 395 | 397 | TP_ARGS(xid, tid, sesid, rc)) |
| 396 | 398 | |
| 397 | 399 | DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(query_info_compound_err); |
| 400 | +DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(posix_query_info_compound_err); | |
| 398 | 401 | DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(hardlink_err); |
| 399 | 402 | DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(rename_err); |
| 400 | 403 | DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(rmdir_err); |