138c8a9a5SSteve French // SPDX-License-Identifier: LGPL-2.1 238c8a9a5SSteve French /* 338c8a9a5SSteve French * 438c8a9a5SSteve French * Copyright (c) International Business Machines Corp., 2003, 2007 538c8a9a5SSteve French * Author(s): Steve French (sfrench@us.ibm.com) 638c8a9a5SSteve French * 738c8a9a5SSteve French */ 838c8a9a5SSteve French 938c8a9a5SSteve French #include <linux/fs.h> 1038c8a9a5SSteve French #include <linux/posix_acl_xattr.h> 1138c8a9a5SSteve French #include <linux/slab.h> 1238c8a9a5SSteve French #include <linux/xattr.h> 1338c8a9a5SSteve French #include "cifsfs.h" 1438c8a9a5SSteve French #include "cifspdu.h" 1538c8a9a5SSteve French #include "cifsglob.h" 1638c8a9a5SSteve French #include "cifsproto.h" 1738c8a9a5SSteve French #include "cifs_debug.h" 1838c8a9a5SSteve French #include "cifs_fs_sb.h" 1938c8a9a5SSteve French #include "cifs_unicode.h" 2038c8a9a5SSteve French #include "cifs_ioctl.h" 2138c8a9a5SSteve French 2238c8a9a5SSteve French #define MAX_EA_VALUE_SIZE CIFSMaxBufSize 2338c8a9a5SSteve French #define CIFS_XATTR_CIFS_ACL "system.cifs_acl" /* DACL only */ 2438c8a9a5SSteve French #define CIFS_XATTR_CIFS_NTSD "system.cifs_ntsd" /* owner plus DACL */ 2538c8a9a5SSteve French #define CIFS_XATTR_CIFS_NTSD_FULL "system.cifs_ntsd_full" /* owner/DACL/SACL */ 2638c8a9a5SSteve French #define CIFS_XATTR_ATTRIB "cifs.dosattrib" /* full name: user.cifs.dosattrib */ 2738c8a9a5SSteve French #define CIFS_XATTR_CREATETIME "cifs.creationtime" /* user.cifs.creationtime */ 2838c8a9a5SSteve French /* 2938c8a9a5SSteve French * Although these three are just aliases for the above, need to move away from 3038c8a9a5SSteve French * confusing users and using the 20+ year old term 'cifs' when it is no longer 3138c8a9a5SSteve French * secure, replaced by SMB2 (then even more highly secure SMB3) many years ago 3238c8a9a5SSteve French */ 3338c8a9a5SSteve French #define SMB3_XATTR_CIFS_ACL "system.smb3_acl" /* DACL only */ 3438c8a9a5SSteve French #define SMB3_XATTR_CIFS_NTSD "system.smb3_ntsd" /* owner plus DACL */ 3538c8a9a5SSteve French #define SMB3_XATTR_CIFS_NTSD_FULL "system.smb3_ntsd_full" /* owner/DACL/SACL */ 3638c8a9a5SSteve French #define SMB3_XATTR_ATTRIB "smb3.dosattrib" /* full name: user.smb3.dosattrib */ 3738c8a9a5SSteve French #define SMB3_XATTR_CREATETIME "smb3.creationtime" /* user.smb3.creationtime */ 3838c8a9a5SSteve French /* BB need to add server (Samba e.g) support for security and trusted prefix */ 3938c8a9a5SSteve French 4038c8a9a5SSteve French enum { XATTR_USER, XATTR_CIFS_ACL, XATTR_ACL_ACCESS, XATTR_ACL_DEFAULT, 4138c8a9a5SSteve French XATTR_CIFS_NTSD, XATTR_CIFS_NTSD_FULL }; 4238c8a9a5SSteve French 4338c8a9a5SSteve French static int cifs_attrib_set(unsigned int xid, struct cifs_tcon *pTcon, 4438c8a9a5SSteve French struct inode *inode, const char *full_path, 4538c8a9a5SSteve French const void *value, size_t size) 4638c8a9a5SSteve French { 4738c8a9a5SSteve French ssize_t rc = -EOPNOTSUPP; 4838c8a9a5SSteve French __u32 *pattrib = (__u32 *)value; 4938c8a9a5SSteve French __u32 attrib; 5038c8a9a5SSteve French FILE_BASIC_INFO info_buf; 5138c8a9a5SSteve French 5238c8a9a5SSteve French if ((value == NULL) || (size != sizeof(__u32))) 5338c8a9a5SSteve French return -ERANGE; 5438c8a9a5SSteve French 5538c8a9a5SSteve French memset(&info_buf, 0, sizeof(info_buf)); 5638c8a9a5SSteve French attrib = *pattrib; 5738c8a9a5SSteve French info_buf.Attributes = cpu_to_le32(attrib); 5838c8a9a5SSteve French if (pTcon->ses->server->ops->set_file_info) 5938c8a9a5SSteve French rc = pTcon->ses->server->ops->set_file_info(inode, full_path, 6038c8a9a5SSteve French &info_buf, xid); 6138c8a9a5SSteve French if (rc == 0) 6238c8a9a5SSteve French CIFS_I(inode)->cifsAttrs = attrib; 6338c8a9a5SSteve French 6438c8a9a5SSteve French return rc; 6538c8a9a5SSteve French } 6638c8a9a5SSteve French 6738c8a9a5SSteve French static int cifs_creation_time_set(unsigned int xid, struct cifs_tcon *pTcon, 6838c8a9a5SSteve French struct inode *inode, const char *full_path, 6938c8a9a5SSteve French const void *value, size_t size) 7038c8a9a5SSteve French { 7138c8a9a5SSteve French ssize_t rc = -EOPNOTSUPP; 7238c8a9a5SSteve French __u64 *pcreation_time = (__u64 *)value; 7338c8a9a5SSteve French __u64 creation_time; 7438c8a9a5SSteve French FILE_BASIC_INFO info_buf; 7538c8a9a5SSteve French 7638c8a9a5SSteve French if ((value == NULL) || (size != sizeof(__u64))) 7738c8a9a5SSteve French return -ERANGE; 7838c8a9a5SSteve French 7938c8a9a5SSteve French memset(&info_buf, 0, sizeof(info_buf)); 8038c8a9a5SSteve French creation_time = *pcreation_time; 8138c8a9a5SSteve French info_buf.CreationTime = cpu_to_le64(creation_time); 8238c8a9a5SSteve French if (pTcon->ses->server->ops->set_file_info) 8338c8a9a5SSteve French rc = pTcon->ses->server->ops->set_file_info(inode, full_path, 8438c8a9a5SSteve French &info_buf, xid); 8538c8a9a5SSteve French if (rc == 0) 8638c8a9a5SSteve French CIFS_I(inode)->createtime = creation_time; 8738c8a9a5SSteve French 8838c8a9a5SSteve French return rc; 8938c8a9a5SSteve French } 9038c8a9a5SSteve French 9138c8a9a5SSteve French static int cifs_xattr_set(const struct xattr_handler *handler, 9238c8a9a5SSteve French struct mnt_idmap *idmap, 9338c8a9a5SSteve French struct dentry *dentry, struct inode *inode, 9438c8a9a5SSteve French const char *name, const void *value, 9538c8a9a5SSteve French size_t size, int flags) 9638c8a9a5SSteve French { 9738c8a9a5SSteve French int rc = -EOPNOTSUPP; 9838c8a9a5SSteve French unsigned int xid; 9938c8a9a5SSteve French struct super_block *sb = dentry->d_sb; 10038c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 10138c8a9a5SSteve French struct tcon_link *tlink; 10238c8a9a5SSteve French struct cifs_tcon *pTcon; 10338c8a9a5SSteve French const char *full_path; 10438c8a9a5SSteve French void *page; 10538c8a9a5SSteve French 10638c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 10738c8a9a5SSteve French if (IS_ERR(tlink)) 10838c8a9a5SSteve French return PTR_ERR(tlink); 10938c8a9a5SSteve French pTcon = tlink_tcon(tlink); 11038c8a9a5SSteve French 11138c8a9a5SSteve French xid = get_xid(); 11238c8a9a5SSteve French page = alloc_dentry_path(); 11338c8a9a5SSteve French 11438c8a9a5SSteve French full_path = build_path_from_dentry(dentry, page); 11538c8a9a5SSteve French if (IS_ERR(full_path)) { 11638c8a9a5SSteve French rc = PTR_ERR(full_path); 11738c8a9a5SSteve French goto out; 11838c8a9a5SSteve French } 11938c8a9a5SSteve French /* return dos attributes as pseudo xattr */ 12038c8a9a5SSteve French /* return alt name if available as pseudo attr */ 12138c8a9a5SSteve French 12238c8a9a5SSteve French /* if proc/fs/cifs/streamstoxattr is set then 12338c8a9a5SSteve French search server for EAs or streams to 12438c8a9a5SSteve French returns as xattrs */ 12538c8a9a5SSteve French if (size > MAX_EA_VALUE_SIZE) { 12638c8a9a5SSteve French cifs_dbg(FYI, "size of EA value too large\n"); 12738c8a9a5SSteve French rc = -EOPNOTSUPP; 12838c8a9a5SSteve French goto out; 12938c8a9a5SSteve French } 13038c8a9a5SSteve French 13138c8a9a5SSteve French switch (handler->flags) { 13238c8a9a5SSteve French case XATTR_USER: 13338c8a9a5SSteve French cifs_dbg(FYI, "%s:setting user xattr %s\n", __func__, name); 13438c8a9a5SSteve French if ((strcmp(name, CIFS_XATTR_ATTRIB) == 0) || 13538c8a9a5SSteve French (strcmp(name, SMB3_XATTR_ATTRIB) == 0)) { 13638c8a9a5SSteve French rc = cifs_attrib_set(xid, pTcon, inode, full_path, 13738c8a9a5SSteve French value, size); 13838c8a9a5SSteve French if (rc == 0) /* force revalidate of the inode */ 13938c8a9a5SSteve French CIFS_I(inode)->time = 0; 14038c8a9a5SSteve French break; 14138c8a9a5SSteve French } else if ((strcmp(name, CIFS_XATTR_CREATETIME) == 0) || 14238c8a9a5SSteve French (strcmp(name, SMB3_XATTR_CREATETIME) == 0)) { 14338c8a9a5SSteve French rc = cifs_creation_time_set(xid, pTcon, inode, 14438c8a9a5SSteve French full_path, value, size); 14538c8a9a5SSteve French if (rc == 0) /* force revalidate of the inode */ 14638c8a9a5SSteve French CIFS_I(inode)->time = 0; 14738c8a9a5SSteve French break; 14838c8a9a5SSteve French } 14938c8a9a5SSteve French 15038c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) 15138c8a9a5SSteve French goto out; 15238c8a9a5SSteve French 153*318e1c7eSSteve French if (pTcon->ses->server->ops->set_EA) { 15438c8a9a5SSteve French rc = pTcon->ses->server->ops->set_EA(xid, pTcon, 15538c8a9a5SSteve French full_path, name, value, (__u16)size, 15638c8a9a5SSteve French cifs_sb->local_nls, cifs_sb); 157*318e1c7eSSteve French if (rc == 0) 158*318e1c7eSSteve French inode_set_ctime_current(inode); 159*318e1c7eSSteve French } 16038c8a9a5SSteve French break; 16138c8a9a5SSteve French 16238c8a9a5SSteve French case XATTR_CIFS_ACL: 16338c8a9a5SSteve French case XATTR_CIFS_NTSD: 16438c8a9a5SSteve French case XATTR_CIFS_NTSD_FULL: { 16538c8a9a5SSteve French struct cifs_ntsd *pacl; 16638c8a9a5SSteve French 16738c8a9a5SSteve French if (!value) 16838c8a9a5SSteve French goto out; 16938c8a9a5SSteve French pacl = kmalloc(size, GFP_KERNEL); 17038c8a9a5SSteve French if (!pacl) { 17138c8a9a5SSteve French rc = -ENOMEM; 17238c8a9a5SSteve French } else { 17338c8a9a5SSteve French memcpy(pacl, value, size); 17438c8a9a5SSteve French if (pTcon->ses->server->ops->set_acl) { 17538c8a9a5SSteve French int aclflags = 0; 17638c8a9a5SSteve French rc = 0; 17738c8a9a5SSteve French 17838c8a9a5SSteve French switch (handler->flags) { 17938c8a9a5SSteve French case XATTR_CIFS_NTSD_FULL: 18038c8a9a5SSteve French aclflags = (CIFS_ACL_OWNER | 18138c8a9a5SSteve French CIFS_ACL_GROUP | 18238c8a9a5SSteve French CIFS_ACL_DACL | 18338c8a9a5SSteve French CIFS_ACL_SACL); 18438c8a9a5SSteve French break; 18538c8a9a5SSteve French case XATTR_CIFS_NTSD: 18638c8a9a5SSteve French aclflags = (CIFS_ACL_OWNER | 18738c8a9a5SSteve French CIFS_ACL_GROUP | 18838c8a9a5SSteve French CIFS_ACL_DACL); 18938c8a9a5SSteve French break; 19038c8a9a5SSteve French case XATTR_CIFS_ACL: 19138c8a9a5SSteve French default: 19238c8a9a5SSteve French aclflags = CIFS_ACL_DACL; 19338c8a9a5SSteve French } 19438c8a9a5SSteve French 19538c8a9a5SSteve French rc = pTcon->ses->server->ops->set_acl(pacl, 19638c8a9a5SSteve French size, inode, full_path, aclflags); 19738c8a9a5SSteve French } else { 19838c8a9a5SSteve French rc = -EOPNOTSUPP; 19938c8a9a5SSteve French } 20038c8a9a5SSteve French if (rc == 0) /* force revalidate of the inode */ 20138c8a9a5SSteve French CIFS_I(inode)->time = 0; 20238c8a9a5SSteve French kfree(pacl); 20338c8a9a5SSteve French } 20438c8a9a5SSteve French break; 20538c8a9a5SSteve French } 20638c8a9a5SSteve French } 20738c8a9a5SSteve French 20838c8a9a5SSteve French out: 20938c8a9a5SSteve French free_dentry_path(page); 21038c8a9a5SSteve French free_xid(xid); 21138c8a9a5SSteve French cifs_put_tlink(tlink); 21238c8a9a5SSteve French return rc; 21338c8a9a5SSteve French } 21438c8a9a5SSteve French 21538c8a9a5SSteve French static int cifs_attrib_get(struct dentry *dentry, 21638c8a9a5SSteve French struct inode *inode, void *value, 21738c8a9a5SSteve French size_t size) 21838c8a9a5SSteve French { 21938c8a9a5SSteve French ssize_t rc; 22038c8a9a5SSteve French __u32 *pattribute; 22138c8a9a5SSteve French 22238c8a9a5SSteve French rc = cifs_revalidate_dentry_attr(dentry); 22338c8a9a5SSteve French 22438c8a9a5SSteve French if (rc) 22538c8a9a5SSteve French return rc; 22638c8a9a5SSteve French 22738c8a9a5SSteve French if ((value == NULL) || (size == 0)) 22838c8a9a5SSteve French return sizeof(__u32); 22938c8a9a5SSteve French else if (size < sizeof(__u32)) 23038c8a9a5SSteve French return -ERANGE; 23138c8a9a5SSteve French 23238c8a9a5SSteve French /* return dos attributes as pseudo xattr */ 23338c8a9a5SSteve French pattribute = (__u32 *)value; 23438c8a9a5SSteve French *pattribute = CIFS_I(inode)->cifsAttrs; 23538c8a9a5SSteve French 23638c8a9a5SSteve French return sizeof(__u32); 23738c8a9a5SSteve French } 23838c8a9a5SSteve French 23938c8a9a5SSteve French static int cifs_creation_time_get(struct dentry *dentry, struct inode *inode, 24038c8a9a5SSteve French void *value, size_t size) 24138c8a9a5SSteve French { 24238c8a9a5SSteve French ssize_t rc; 24338c8a9a5SSteve French __u64 *pcreatetime; 24438c8a9a5SSteve French 24538c8a9a5SSteve French rc = cifs_revalidate_dentry_attr(dentry); 24638c8a9a5SSteve French if (rc) 24738c8a9a5SSteve French return rc; 24838c8a9a5SSteve French 24938c8a9a5SSteve French if ((value == NULL) || (size == 0)) 25038c8a9a5SSteve French return sizeof(__u64); 25138c8a9a5SSteve French else if (size < sizeof(__u64)) 25238c8a9a5SSteve French return -ERANGE; 25338c8a9a5SSteve French 25438c8a9a5SSteve French /* return dos attributes as pseudo xattr */ 25538c8a9a5SSteve French pcreatetime = (__u64 *)value; 25638c8a9a5SSteve French *pcreatetime = CIFS_I(inode)->createtime; 25738c8a9a5SSteve French return sizeof(__u64); 25838c8a9a5SSteve French } 25938c8a9a5SSteve French 26038c8a9a5SSteve French 26138c8a9a5SSteve French static int cifs_xattr_get(const struct xattr_handler *handler, 26238c8a9a5SSteve French struct dentry *dentry, struct inode *inode, 26338c8a9a5SSteve French const char *name, void *value, size_t size) 26438c8a9a5SSteve French { 26538c8a9a5SSteve French ssize_t rc = -EOPNOTSUPP; 26638c8a9a5SSteve French unsigned int xid; 26738c8a9a5SSteve French struct super_block *sb = dentry->d_sb; 26838c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 26938c8a9a5SSteve French struct tcon_link *tlink; 27038c8a9a5SSteve French struct cifs_tcon *pTcon; 27138c8a9a5SSteve French const char *full_path; 27238c8a9a5SSteve French void *page; 27338c8a9a5SSteve French 27438c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 27538c8a9a5SSteve French if (IS_ERR(tlink)) 27638c8a9a5SSteve French return PTR_ERR(tlink); 27738c8a9a5SSteve French pTcon = tlink_tcon(tlink); 27838c8a9a5SSteve French 27938c8a9a5SSteve French xid = get_xid(); 28038c8a9a5SSteve French page = alloc_dentry_path(); 28138c8a9a5SSteve French 28238c8a9a5SSteve French full_path = build_path_from_dentry(dentry, page); 28338c8a9a5SSteve French if (IS_ERR(full_path)) { 28438c8a9a5SSteve French rc = PTR_ERR(full_path); 28538c8a9a5SSteve French goto out; 28638c8a9a5SSteve French } 28738c8a9a5SSteve French 28838c8a9a5SSteve French /* return alt name if available as pseudo attr */ 28938c8a9a5SSteve French switch (handler->flags) { 29038c8a9a5SSteve French case XATTR_USER: 29138c8a9a5SSteve French cifs_dbg(FYI, "%s:querying user xattr %s\n", __func__, name); 29238c8a9a5SSteve French if ((strcmp(name, CIFS_XATTR_ATTRIB) == 0) || 29338c8a9a5SSteve French (strcmp(name, SMB3_XATTR_ATTRIB) == 0)) { 29438c8a9a5SSteve French rc = cifs_attrib_get(dentry, inode, value, size); 29538c8a9a5SSteve French break; 29638c8a9a5SSteve French } else if ((strcmp(name, CIFS_XATTR_CREATETIME) == 0) || 29738c8a9a5SSteve French (strcmp(name, SMB3_XATTR_CREATETIME) == 0)) { 29838c8a9a5SSteve French rc = cifs_creation_time_get(dentry, inode, value, size); 29938c8a9a5SSteve French break; 30038c8a9a5SSteve French } 30138c8a9a5SSteve French 30238c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) 30338c8a9a5SSteve French goto out; 30438c8a9a5SSteve French 30538c8a9a5SSteve French if (pTcon->ses->server->ops->query_all_EAs) 30638c8a9a5SSteve French rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, 30738c8a9a5SSteve French full_path, name, value, size, cifs_sb); 30838c8a9a5SSteve French break; 30938c8a9a5SSteve French 31038c8a9a5SSteve French case XATTR_CIFS_ACL: 31138c8a9a5SSteve French case XATTR_CIFS_NTSD: 31238c8a9a5SSteve French case XATTR_CIFS_NTSD_FULL: { 31338c8a9a5SSteve French /* 31438c8a9a5SSteve French * fetch owner, DACL, and SACL if asked for full descriptor, 31538c8a9a5SSteve French * fetch owner and DACL otherwise 31638c8a9a5SSteve French */ 31738c8a9a5SSteve French u32 acllen, extra_info; 31838c8a9a5SSteve French struct cifs_ntsd *pacl; 31938c8a9a5SSteve French 32038c8a9a5SSteve French if (pTcon->ses->server->ops->get_acl == NULL) 32138c8a9a5SSteve French goto out; /* rc already EOPNOTSUPP */ 32238c8a9a5SSteve French 32338c8a9a5SSteve French if (handler->flags == XATTR_CIFS_NTSD_FULL) { 32438c8a9a5SSteve French extra_info = SACL_SECINFO; 32538c8a9a5SSteve French } else { 32638c8a9a5SSteve French extra_info = 0; 32738c8a9a5SSteve French } 32838c8a9a5SSteve French pacl = pTcon->ses->server->ops->get_acl(cifs_sb, 32938c8a9a5SSteve French inode, full_path, &acllen, extra_info); 33038c8a9a5SSteve French if (IS_ERR(pacl)) { 33138c8a9a5SSteve French rc = PTR_ERR(pacl); 33238c8a9a5SSteve French cifs_dbg(VFS, "%s: error %zd getting sec desc\n", 33338c8a9a5SSteve French __func__, rc); 33438c8a9a5SSteve French } else { 33538c8a9a5SSteve French if (value) { 33638c8a9a5SSteve French if (acllen > size) 33738c8a9a5SSteve French acllen = -ERANGE; 33838c8a9a5SSteve French else 33938c8a9a5SSteve French memcpy(value, pacl, acllen); 34038c8a9a5SSteve French } 34138c8a9a5SSteve French rc = acllen; 34238c8a9a5SSteve French kfree(pacl); 34338c8a9a5SSteve French } 34438c8a9a5SSteve French break; 34538c8a9a5SSteve French } 34638c8a9a5SSteve French } 34738c8a9a5SSteve French 34838c8a9a5SSteve French /* We could add an additional check for streams ie 34938c8a9a5SSteve French if proc/fs/cifs/streamstoxattr is set then 35038c8a9a5SSteve French search server for EAs or streams to 35138c8a9a5SSteve French returns as xattrs */ 35238c8a9a5SSteve French 35338c8a9a5SSteve French if (rc == -EINVAL) 35438c8a9a5SSteve French rc = -EOPNOTSUPP; 35538c8a9a5SSteve French 35638c8a9a5SSteve French out: 35738c8a9a5SSteve French free_dentry_path(page); 35838c8a9a5SSteve French free_xid(xid); 35938c8a9a5SSteve French cifs_put_tlink(tlink); 36038c8a9a5SSteve French return rc; 36138c8a9a5SSteve French } 36238c8a9a5SSteve French 36338c8a9a5SSteve French ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) 36438c8a9a5SSteve French { 36538c8a9a5SSteve French ssize_t rc = -EOPNOTSUPP; 36638c8a9a5SSteve French unsigned int xid; 36738c8a9a5SSteve French struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); 36838c8a9a5SSteve French struct tcon_link *tlink; 36938c8a9a5SSteve French struct cifs_tcon *pTcon; 37038c8a9a5SSteve French const char *full_path; 37138c8a9a5SSteve French void *page; 37238c8a9a5SSteve French 37338c8a9a5SSteve French if (unlikely(cifs_forced_shutdown(cifs_sb))) 37438c8a9a5SSteve French return -EIO; 37538c8a9a5SSteve French 37638c8a9a5SSteve French if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) 37738c8a9a5SSteve French return -EOPNOTSUPP; 37838c8a9a5SSteve French 37938c8a9a5SSteve French tlink = cifs_sb_tlink(cifs_sb); 38038c8a9a5SSteve French if (IS_ERR(tlink)) 38138c8a9a5SSteve French return PTR_ERR(tlink); 38238c8a9a5SSteve French pTcon = tlink_tcon(tlink); 38338c8a9a5SSteve French 38438c8a9a5SSteve French xid = get_xid(); 38538c8a9a5SSteve French page = alloc_dentry_path(); 38638c8a9a5SSteve French 38738c8a9a5SSteve French full_path = build_path_from_dentry(direntry, page); 38838c8a9a5SSteve French if (IS_ERR(full_path)) { 38938c8a9a5SSteve French rc = PTR_ERR(full_path); 39038c8a9a5SSteve French goto list_ea_exit; 39138c8a9a5SSteve French } 39238c8a9a5SSteve French /* return dos attributes as pseudo xattr */ 39338c8a9a5SSteve French /* return alt name if available as pseudo attr */ 39438c8a9a5SSteve French 39538c8a9a5SSteve French /* if proc/fs/cifs/streamstoxattr is set then 39638c8a9a5SSteve French search server for EAs or streams to 39738c8a9a5SSteve French returns as xattrs */ 39838c8a9a5SSteve French 39938c8a9a5SSteve French if (pTcon->ses->server->ops->query_all_EAs) 40038c8a9a5SSteve French rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, 40138c8a9a5SSteve French full_path, NULL, data, buf_size, cifs_sb); 40238c8a9a5SSteve French list_ea_exit: 40338c8a9a5SSteve French free_dentry_path(page); 40438c8a9a5SSteve French free_xid(xid); 40538c8a9a5SSteve French cifs_put_tlink(tlink); 40638c8a9a5SSteve French return rc; 40738c8a9a5SSteve French } 40838c8a9a5SSteve French 40938c8a9a5SSteve French static const struct xattr_handler cifs_user_xattr_handler = { 41038c8a9a5SSteve French .prefix = XATTR_USER_PREFIX, 41138c8a9a5SSteve French .flags = XATTR_USER, 41238c8a9a5SSteve French .get = cifs_xattr_get, 41338c8a9a5SSteve French .set = cifs_xattr_set, 41438c8a9a5SSteve French }; 41538c8a9a5SSteve French 41638c8a9a5SSteve French /* os2.* attributes are treated like user.* attributes */ 41738c8a9a5SSteve French static const struct xattr_handler cifs_os2_xattr_handler = { 41838c8a9a5SSteve French .prefix = XATTR_OS2_PREFIX, 41938c8a9a5SSteve French .flags = XATTR_USER, 42038c8a9a5SSteve French .get = cifs_xattr_get, 42138c8a9a5SSteve French .set = cifs_xattr_set, 42238c8a9a5SSteve French }; 42338c8a9a5SSteve French 42438c8a9a5SSteve French static const struct xattr_handler cifs_cifs_acl_xattr_handler = { 42538c8a9a5SSteve French .name = CIFS_XATTR_CIFS_ACL, 42638c8a9a5SSteve French .flags = XATTR_CIFS_ACL, 42738c8a9a5SSteve French .get = cifs_xattr_get, 42838c8a9a5SSteve French .set = cifs_xattr_set, 42938c8a9a5SSteve French }; 43038c8a9a5SSteve French 43138c8a9a5SSteve French /* 43238c8a9a5SSteve French * Although this is just an alias for the above, need to move away from 43338c8a9a5SSteve French * confusing users and using the 20 year old term 'cifs' when it is no 43438c8a9a5SSteve French * longer secure and was replaced by SMB2/SMB3 a long time ago, and 43538c8a9a5SSteve French * SMB3 and later are highly secure. 43638c8a9a5SSteve French */ 43738c8a9a5SSteve French static const struct xattr_handler smb3_acl_xattr_handler = { 43838c8a9a5SSteve French .name = SMB3_XATTR_CIFS_ACL, 43938c8a9a5SSteve French .flags = XATTR_CIFS_ACL, 44038c8a9a5SSteve French .get = cifs_xattr_get, 44138c8a9a5SSteve French .set = cifs_xattr_set, 44238c8a9a5SSteve French }; 44338c8a9a5SSteve French 44438c8a9a5SSteve French static const struct xattr_handler cifs_cifs_ntsd_xattr_handler = { 44538c8a9a5SSteve French .name = CIFS_XATTR_CIFS_NTSD, 44638c8a9a5SSteve French .flags = XATTR_CIFS_NTSD, 44738c8a9a5SSteve French .get = cifs_xattr_get, 44838c8a9a5SSteve French .set = cifs_xattr_set, 44938c8a9a5SSteve French }; 45038c8a9a5SSteve French 45138c8a9a5SSteve French /* 45238c8a9a5SSteve French * Although this is just an alias for the above, need to move away from 45338c8a9a5SSteve French * confusing users and using the 20 year old term 'cifs' when it is no 45438c8a9a5SSteve French * longer secure and was replaced by SMB2/SMB3 a long time ago, and 45538c8a9a5SSteve French * SMB3 and later are highly secure. 45638c8a9a5SSteve French */ 45738c8a9a5SSteve French static const struct xattr_handler smb3_ntsd_xattr_handler = { 45838c8a9a5SSteve French .name = SMB3_XATTR_CIFS_NTSD, 45938c8a9a5SSteve French .flags = XATTR_CIFS_NTSD, 46038c8a9a5SSteve French .get = cifs_xattr_get, 46138c8a9a5SSteve French .set = cifs_xattr_set, 46238c8a9a5SSteve French }; 46338c8a9a5SSteve French 46438c8a9a5SSteve French static const struct xattr_handler cifs_cifs_ntsd_full_xattr_handler = { 46538c8a9a5SSteve French .name = CIFS_XATTR_CIFS_NTSD_FULL, 46638c8a9a5SSteve French .flags = XATTR_CIFS_NTSD_FULL, 46738c8a9a5SSteve French .get = cifs_xattr_get, 46838c8a9a5SSteve French .set = cifs_xattr_set, 46938c8a9a5SSteve French }; 47038c8a9a5SSteve French 47138c8a9a5SSteve French /* 47238c8a9a5SSteve French * Although this is just an alias for the above, need to move away from 47338c8a9a5SSteve French * confusing users and using the 20 year old term 'cifs' when it is no 47438c8a9a5SSteve French * longer secure and was replaced by SMB2/SMB3 a long time ago, and 47538c8a9a5SSteve French * SMB3 and later are highly secure. 47638c8a9a5SSteve French */ 47738c8a9a5SSteve French static const struct xattr_handler smb3_ntsd_full_xattr_handler = { 47838c8a9a5SSteve French .name = SMB3_XATTR_CIFS_NTSD_FULL, 47938c8a9a5SSteve French .flags = XATTR_CIFS_NTSD_FULL, 48038c8a9a5SSteve French .get = cifs_xattr_get, 48138c8a9a5SSteve French .set = cifs_xattr_set, 48238c8a9a5SSteve French }; 48338c8a9a5SSteve French 48438c8a9a5SSteve French const struct xattr_handler *cifs_xattr_handlers[] = { 48538c8a9a5SSteve French &cifs_user_xattr_handler, 48638c8a9a5SSteve French &cifs_os2_xattr_handler, 48738c8a9a5SSteve French &cifs_cifs_acl_xattr_handler, 48838c8a9a5SSteve French &smb3_acl_xattr_handler, /* alias for above since avoiding "cifs" */ 48938c8a9a5SSteve French &cifs_cifs_ntsd_xattr_handler, 49038c8a9a5SSteve French &smb3_ntsd_xattr_handler, /* alias for above since avoiding "cifs" */ 49138c8a9a5SSteve French &cifs_cifs_ntsd_full_xattr_handler, 49238c8a9a5SSteve French &smb3_ntsd_full_xattr_handler, /* alias for above since avoiding "cifs" */ 49338c8a9a5SSteve French NULL 49438c8a9a5SSteve French }; 495