diff options
Diffstat (limited to 'fs/cifs/xattr.c')
| -rw-r--r-- | fs/cifs/xattr.c | 148 | 
1 files changed, 95 insertions, 53 deletions
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index b8299173ea7e..998fa51f9b68 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -1,22 +1,9 @@ +// SPDX-License-Identifier: LGPL-2.1  /* - *   fs/cifs/xattr.c   *   *   Copyright (c) International Business Machines  Corp., 2003, 2007   *   Author(s): Steve French (sfrench@us.ibm.com)   * - *   This library is free software; you can redistribute it and/or modify - *   it under the terms of the GNU Lesser General Public License as published - *   by the Free Software Foundation; either version 2.1 of the License, or - *   (at your option) any later version. - * - *   This library is distributed in the hope that it will be useful, - *   but WITHOUT ANY WARRANTY; without even the implied warranty of - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See - *   the GNU Lesser General Public License for more details. - * - *   You should have received a copy of the GNU Lesser General Public License - *   along with this library; if not, write to the Free Software - *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA   */  #include <linux/fs.h> @@ -30,10 +17,12 @@  #include "cifs_debug.h"  #include "cifs_fs_sb.h"  #include "cifs_unicode.h" +#include "cifs_ioctl.h"  #define MAX_EA_VALUE_SIZE CIFSMaxBufSize  #define CIFS_XATTR_CIFS_ACL "system.cifs_acl" /* DACL only */  #define CIFS_XATTR_CIFS_NTSD "system.cifs_ntsd" /* owner plus DACL */ +#define CIFS_XATTR_CIFS_NTSD_FULL "system.cifs_ntsd_full" /* owner/DACL/SACL */  #define CIFS_XATTR_ATTRIB "cifs.dosattrib"  /* full name: user.cifs.dosattrib */  #define CIFS_XATTR_CREATETIME "cifs.creationtime"  /* user.cifs.creationtime */  /* @@ -43,15 +32,16 @@   */  #define SMB3_XATTR_CIFS_ACL "system.smb3_acl" /* DACL only */  #define SMB3_XATTR_CIFS_NTSD "system.smb3_ntsd" /* owner plus DACL */ +#define SMB3_XATTR_CIFS_NTSD_FULL "system.smb3_ntsd_full" /* owner/DACL/SACL */  #define SMB3_XATTR_ATTRIB "smb3.dosattrib"  /* full name: user.smb3.dosattrib */  #define SMB3_XATTR_CREATETIME "smb3.creationtime"  /* user.smb3.creationtime */  /* BB need to add server (Samba e.g) support for security and trusted prefix */  enum { XATTR_USER, XATTR_CIFS_ACL, XATTR_ACL_ACCESS, XATTR_ACL_DEFAULT, -	XATTR_CIFS_NTSD }; +	XATTR_CIFS_NTSD, XATTR_CIFS_NTSD_FULL };  static int cifs_attrib_set(unsigned int xid, struct cifs_tcon *pTcon, -			   struct inode *inode, char *full_path, +			   struct inode *inode, const char *full_path,  			   const void *value, size_t size)  {  	ssize_t rc = -EOPNOTSUPP; @@ -75,7 +65,7 @@ static int cifs_attrib_set(unsigned int xid, struct cifs_tcon *pTcon,  }  static int cifs_creation_time_set(unsigned int xid, struct cifs_tcon *pTcon, -				  struct inode *inode, char *full_path, +				  struct inode *inode, const char *full_path,  				  const void *value, size_t size)  {  	ssize_t rc = -EOPNOTSUPP; @@ -99,6 +89,7 @@ static int cifs_creation_time_set(unsigned int xid, struct cifs_tcon *pTcon,  }  static int cifs_xattr_set(const struct xattr_handler *handler, +			  struct user_namespace *mnt_userns,  			  struct dentry *dentry, struct inode *inode,  			  const char *name, const void *value,  			  size_t size, int flags) @@ -109,7 +100,8 @@ static int cifs_xattr_set(const struct xattr_handler *handler,  	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);  	struct tcon_link *tlink;  	struct cifs_tcon *pTcon; -	char *full_path; +	const char *full_path; +	void *page;  	tlink = cifs_sb_tlink(cifs_sb);  	if (IS_ERR(tlink)) @@ -117,10 +109,11 @@ static int cifs_xattr_set(const struct xattr_handler *handler,  	pTcon = tlink_tcon(tlink);  	xid = get_xid(); +	page = alloc_dentry_path(); -	full_path = build_path_from_dentry(dentry); -	if (full_path == NULL) { -		rc = -ENOMEM; +	full_path = build_path_from_dentry(dentry, page); +	if (IS_ERR(full_path)) { +		rc = PTR_ERR(full_path);  		goto out;  	}  	/* return dos attributes as pseudo xattr */ @@ -164,7 +157,8 @@ static int cifs_xattr_set(const struct xattr_handler *handler,  		break;  	case XATTR_CIFS_ACL: -	case XATTR_CIFS_NTSD: { +	case XATTR_CIFS_NTSD: +	case XATTR_CIFS_NTSD_FULL: {  		struct cifs_ntsd *pacl;  		if (!value) @@ -174,23 +168,29 @@ static int cifs_xattr_set(const struct xattr_handler *handler,  			rc = -ENOMEM;  		} else {  			memcpy(pacl, value, size); -			if (value && -			    pTcon->ses->server->ops->set_acl) { +			if (pTcon->ses->server->ops->set_acl) { +				int aclflags = 0;  				rc = 0; -				if (handler->flags == XATTR_CIFS_NTSD) { -					/* set owner and DACL */ -					rc = pTcon->ses->server->ops->set_acl( -							pacl, size, inode, -							full_path, -							CIFS_ACL_OWNER); -				} -				if (rc == 0) { -					/* set DACL */ -					rc = pTcon->ses->server->ops->set_acl( -							pacl, size, inode, -							full_path, -							CIFS_ACL_DACL); + +				switch (handler->flags) { +				case XATTR_CIFS_NTSD_FULL: +					aclflags = (CIFS_ACL_OWNER | +						    CIFS_ACL_GROUP | +						    CIFS_ACL_DACL | +						    CIFS_ACL_SACL); +					break; +				case XATTR_CIFS_NTSD: +					aclflags = (CIFS_ACL_OWNER | +						    CIFS_ACL_GROUP | +						    CIFS_ACL_DACL); +					break; +				case XATTR_CIFS_ACL: +				default: +					aclflags = CIFS_ACL_DACL;  				} + +				rc = pTcon->ses->server->ops->set_acl(pacl, +					size, inode, full_path, aclflags);  			} else {  				rc = -EOPNOTSUPP;  			} @@ -201,6 +201,7 @@ static int cifs_xattr_set(const struct xattr_handler *handler,  		break;  	} +#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY  	case XATTR_ACL_ACCESS:  #ifdef CONFIG_CIFS_POSIX  		if (!value) @@ -224,10 +225,11 @@ static int cifs_xattr_set(const struct xattr_handler *handler,  				cifs_remap(cifs_sb));  #endif  /* CONFIG_CIFS_POSIX */  		break; +#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */  	}  out: -	kfree(full_path); +	free_dentry_path(page);  	free_xid(xid);  	cifs_put_tlink(tlink);  	return rc; @@ -289,7 +291,8 @@ static int cifs_xattr_get(const struct xattr_handler *handler,  	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);  	struct tcon_link *tlink;  	struct cifs_tcon *pTcon; -	char *full_path; +	const char *full_path; +	void *page;  	tlink = cifs_sb_tlink(cifs_sb);  	if (IS_ERR(tlink)) @@ -297,10 +300,11 @@ static int cifs_xattr_get(const struct xattr_handler *handler,  	pTcon = tlink_tcon(tlink);  	xid = get_xid(); +	page = alloc_dentry_path(); -	full_path = build_path_from_dentry(dentry); -	if (full_path == NULL) { -		rc = -ENOMEM; +	full_path = build_path_from_dentry(dentry, page); +	if (IS_ERR(full_path)) { +		rc = PTR_ERR(full_path);  		goto out;  	} @@ -327,16 +331,25 @@ static int cifs_xattr_get(const struct xattr_handler *handler,  		break;  	case XATTR_CIFS_ACL: -	case XATTR_CIFS_NTSD: { -		/* the whole ntsd is fetched regardless */ -		u32 acllen; +	case XATTR_CIFS_NTSD: +	case XATTR_CIFS_NTSD_FULL: { +		/* +		 * fetch owner, DACL, and SACL if asked for full descriptor, +		 * fetch owner and DACL otherwise +		 */ +		u32 acllen, extra_info;  		struct cifs_ntsd *pacl;  		if (pTcon->ses->server->ops->get_acl == NULL)  			goto out; /* rc already EOPNOTSUPP */ +		if (handler->flags == XATTR_CIFS_NTSD_FULL) { +			extra_info = SACL_SECINFO; +		} else { +			extra_info = 0; +		}  		pacl = pTcon->ses->server->ops->get_acl(cifs_sb, -				inode, full_path, &acllen); +				inode, full_path, &acllen, extra_info);  		if (IS_ERR(pacl)) {  			rc = PTR_ERR(pacl);  			cifs_dbg(VFS, "%s: error %zd getting sec desc\n", @@ -353,7 +366,7 @@ static int cifs_xattr_get(const struct xattr_handler *handler,  		}  		break;  	} - +#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY  	case XATTR_ACL_ACCESS:  #ifdef CONFIG_CIFS_POSIX  		if (sb->s_flags & SB_POSIXACL) @@ -373,6 +386,7 @@ static int cifs_xattr_get(const struct xattr_handler *handler,  				cifs_remap(cifs_sb));  #endif  /* CONFIG_CIFS_POSIX */  		break; +#endif /* ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY */  	}  	/* We could add an additional check for streams ie @@ -384,7 +398,7 @@ static int cifs_xattr_get(const struct xattr_handler *handler,  		rc = -EOPNOTSUPP;  out: -	kfree(full_path); +	free_dentry_path(page);  	free_xid(xid);  	cifs_put_tlink(tlink);  	return rc; @@ -397,7 +411,11 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)  	struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);  	struct tcon_link *tlink;  	struct cifs_tcon *pTcon; -	char *full_path; +	const char *full_path; +	void *page; + +	if (unlikely(cifs_forced_shutdown(cifs_sb))) +		return -EIO;  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)  		return -EOPNOTSUPP; @@ -408,10 +426,11 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)  	pTcon = tlink_tcon(tlink);  	xid = get_xid(); +	page = alloc_dentry_path(); -	full_path = build_path_from_dentry(direntry); -	if (full_path == NULL) { -		rc = -ENOMEM; +	full_path = build_path_from_dentry(direntry, page); +	if (IS_ERR(full_path)) { +		rc = PTR_ERR(full_path);  		goto list_ea_exit;  	}  	/* return dos attributes as pseudo xattr */ @@ -425,7 +444,7 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)  		rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,  				full_path, NULL, data, buf_size, cifs_sb);  list_ea_exit: -	kfree(full_path); +	free_dentry_path(page);  	free_xid(xid);  	cifs_put_tlink(tlink);  	return rc; @@ -486,6 +505,27 @@ static const struct xattr_handler smb3_ntsd_xattr_handler = {  	.set = cifs_xattr_set,  }; +static const struct xattr_handler cifs_cifs_ntsd_full_xattr_handler = { +	.name = CIFS_XATTR_CIFS_NTSD_FULL, +	.flags = XATTR_CIFS_NTSD_FULL, +	.get = cifs_xattr_get, +	.set = cifs_xattr_set, +}; + +/* + * Although this is just an alias for the above, need to move away from + * confusing users and using the 20 year old term 'cifs' when it is no + * longer secure and was replaced by SMB2/SMB3 a long time ago, and + * SMB3 and later are highly secure. + */ +static const struct xattr_handler smb3_ntsd_full_xattr_handler = { +	.name = SMB3_XATTR_CIFS_NTSD_FULL, +	.flags = XATTR_CIFS_NTSD_FULL, +	.get = cifs_xattr_get, +	.set = cifs_xattr_set, +}; + +  static const struct xattr_handler cifs_posix_acl_access_xattr_handler = {  	.name = XATTR_NAME_POSIX_ACL_ACCESS,  	.flags = XATTR_ACL_ACCESS, @@ -507,6 +547,8 @@ const struct xattr_handler *cifs_xattr_handlers[] = {  	&smb3_acl_xattr_handler, /* alias for above since avoiding "cifs" */  	&cifs_cifs_ntsd_xattr_handler,  	&smb3_ntsd_xattr_handler, /* alias for above since avoiding "cifs" */ +	&cifs_cifs_ntsd_full_xattr_handler, +	&smb3_ntsd_full_xattr_handler, /* alias for above since avoiding "cifs" */  	&cifs_posix_acl_access_xattr_handler,  	&cifs_posix_acl_default_xattr_handler,  	NULL  | 
