diff options
Diffstat (limited to 'fs/cifs/xattr.c')
| -rw-r--r-- | fs/cifs/xattr.c | 239 | 
1 files changed, 138 insertions, 101 deletions
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index a264b744bb4..5ac836a86b1 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -22,6 +22,7 @@  #include <linux/fs.h>  #include <linux/posix_acl_xattr.h>  #include <linux/slab.h> +#include <linux/xattr.h>  #include "cifsfs.h"  #include "cifspdu.h"  #include "cifsglob.h" @@ -30,25 +31,18 @@  #define MAX_EA_VALUE_SIZE 65535  #define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib" -#define CIFS_XATTR_USER_PREFIX "user." -#define CIFS_XATTR_SYSTEM_PREFIX "system." -#define CIFS_XATTR_OS2_PREFIX "os2." -#define CIFS_XATTR_SECURITY_PREFIX ".security" -#define CIFS_XATTR_TRUSTED_PREFIX "trusted." -#define XATTR_TRUSTED_PREFIX_LEN  8 -#define XATTR_SECURITY_PREFIX_LEN 9 -/* BB need to add server (Samba e.g) support for security and trusted prefix */ - +#define CIFS_XATTR_CIFS_ACL "system.cifs_acl" +/* BB need to add server (Samba e.g) support for security and trusted prefix */  int cifs_removexattr(struct dentry *direntry, const char *ea_name)  {  	int rc = -EOPNOTSUPP;  #ifdef CONFIG_CIFS_XATTR -	int xid; +	unsigned int xid;  	struct cifs_sb_info *cifs_sb;  	struct tcon_link *tlink; -	struct cifsTconInfo *pTcon; +	struct cifs_tcon *pTcon;  	struct super_block *sb;  	char *full_path = NULL; @@ -66,7 +60,7 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name)  		return PTR_ERR(tlink);  	pTcon = tlink_tcon(tlink); -	xid = GetXid(); +	xid = get_xid();  	full_path = build_path_from_dentry(direntry);  	if (full_path == NULL) { @@ -74,12 +68,12 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name)  		goto remove_ea_exit;  	}  	if (ea_name == NULL) { -		cFYI(1, "Null xattr names not supported"); -	} else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) -		&& (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4))) { -		cFYI(1, -		     "illegal xattr request %s (only user namespace supported)", -		     ea_name); +		cifs_dbg(FYI, "Null xattr names not supported\n"); +	} else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) +		&& (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN))) { +		cifs_dbg(FYI, +			 "illegal xattr request %s (only user namespace supported)\n", +			 ea_name);  		/* BB what if no namespace prefix? */  		/* Should we just pass them to server, except for  		system and perhaps security prefixes? */ @@ -87,14 +81,16 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name)  		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)  			goto remove_ea_exit; -		ea_name += 5; /* skip past user. prefix */ -		rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, NULL, -			(__u16)0, cifs_sb->local_nls, -			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); +		ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */ +		if (pTcon->ses->server->ops->set_EA) +			rc = pTcon->ses->server->ops->set_EA(xid, pTcon, +				full_path, ea_name, NULL, (__u16)0, +				cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & +					CIFS_MOUNT_MAP_SPECIAL_CHR);  	}  remove_ea_exit:  	kfree(full_path); -	FreeXid(xid); +	free_xid(xid);  	cifs_put_tlink(tlink);  #endif  	return rc; @@ -105,10 +101,10 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,  {  	int rc = -EOPNOTSUPP;  #ifdef CONFIG_CIFS_XATTR -	int xid; +	unsigned int xid;  	struct cifs_sb_info *cifs_sb;  	struct tcon_link *tlink; -	struct cifsTconInfo *pTcon; +	struct cifs_tcon *pTcon;  	struct super_block *sb;  	char *full_path; @@ -126,7 +122,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,  		return PTR_ERR(tlink);  	pTcon = tlink_tcon(tlink); -	xid = GetXid(); +	xid = get_xid();  	full_path = build_path_from_dentry(direntry);  	if (full_path == NULL) { @@ -140,31 +136,59 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,  		search server for EAs or streams to  		returns as xattrs */  	if (value_size > MAX_EA_VALUE_SIZE) { -		cFYI(1, "size of EA value too large"); +		cifs_dbg(FYI, "size of EA value too large\n");  		rc = -EOPNOTSUPP;  		goto set_ea_exit;  	}  	if (ea_name == NULL) { -		cFYI(1, "Null xattr names not supported"); -	} else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) == 0) { +		cifs_dbg(FYI, "Null xattr names not supported\n"); +	} else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) +		   == 0) {  		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)  			goto set_ea_exit;  		if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0) -			cFYI(1, "attempt to set cifs inode metadata"); +			cifs_dbg(FYI, "attempt to set cifs inode metadata\n"); -		ea_name += 5; /* skip past user. prefix */ -		rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value, -			(__u16)value_size, cifs_sb->local_nls, -			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); -	} else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) { +		ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */ +		if (pTcon->ses->server->ops->set_EA) +			rc = pTcon->ses->server->ops->set_EA(xid, pTcon, +				full_path, ea_name, ea_value, (__u16)value_size, +				cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & +					CIFS_MOUNT_MAP_SPECIAL_CHR); +	} else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) +		   == 0) {  		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)  			goto set_ea_exit; -		ea_name += 4; /* skip past os2. prefix */ -		rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value, -			(__u16)value_size, cifs_sb->local_nls, -			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); +		ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */ +		if (pTcon->ses->server->ops->set_EA) +			rc = pTcon->ses->server->ops->set_EA(xid, pTcon, +				full_path, ea_name, ea_value, (__u16)value_size, +				cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & +					CIFS_MOUNT_MAP_SPECIAL_CHR); +	} else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL, +			strlen(CIFS_XATTR_CIFS_ACL)) == 0) { +#ifdef CONFIG_CIFS_ACL +		struct cifs_ntsd *pacl; +		pacl = kmalloc(value_size, GFP_KERNEL); +		if (!pacl) { +			rc = -ENOMEM; +		} else { +			memcpy(pacl, ea_value, value_size); +			if (pTcon->ses->server->ops->set_acl) +				rc = pTcon->ses->server->ops->set_acl(pacl, +						value_size, direntry->d_inode, +						full_path, CIFS_ACL_DACL); +			else +				rc = -EOPNOTSUPP; +			if (rc == 0) /* force revalidate of the inode */ +				CIFS_I(direntry->d_inode)->time = 0; +			kfree(pacl); +		} +#else +		cifs_dbg(FYI, "Set CIFS ACL not supported yet\n"); +#endif /* CONFIG_CIFS_ACL */  	} else {  		int temp;  		temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS, @@ -177,9 +201,9 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,  					ACL_TYPE_ACCESS, cifs_sb->local_nls,  					cifs_sb->mnt_cifs_flags &  						CIFS_MOUNT_MAP_SPECIAL_CHR); -			cFYI(1, "set POSIX ACL rc %d", rc); +			cifs_dbg(FYI, "set POSIX ACL rc %d\n", rc);  #else -			cFYI(1, "set POSIX ACL not supported"); +			cifs_dbg(FYI, "set POSIX ACL not supported\n");  #endif  		} else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,  				   strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { @@ -190,13 +214,13 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,  					ACL_TYPE_DEFAULT, cifs_sb->local_nls,  					cifs_sb->mnt_cifs_flags &  						CIFS_MOUNT_MAP_SPECIAL_CHR); -			cFYI(1, "set POSIX default ACL rc %d", rc); +			cifs_dbg(FYI, "set POSIX default ACL rc %d\n", rc);  #else -			cFYI(1, "set default POSIX ACL not supported"); +			cifs_dbg(FYI, "set default POSIX ACL not supported\n");  #endif  		} else { -			cFYI(1, "illegal xattr request %s (only user namespace" -				" supported)", ea_name); +			cifs_dbg(FYI, "illegal xattr request %s (only user namespace supported)\n", +				 ea_name);  		  /* BB what if no namespace prefix? */  		  /* Should we just pass them to server, except for  		  system and perhaps security prefixes? */ @@ -205,7 +229,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,  set_ea_exit:  	kfree(full_path); -	FreeXid(xid); +	free_xid(xid);  	cifs_put_tlink(tlink);  #endif  	return rc; @@ -216,10 +240,10 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,  {  	ssize_t rc = -EOPNOTSUPP;  #ifdef CONFIG_CIFS_XATTR -	int xid; +	unsigned int xid;  	struct cifs_sb_info *cifs_sb;  	struct tcon_link *tlink; -	struct cifsTconInfo *pTcon; +	struct cifs_tcon *pTcon;  	struct super_block *sb;  	char *full_path; @@ -237,7 +261,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,  		return PTR_ERR(tlink);  	pTcon = tlink_tcon(tlink); -	xid = GetXid(); +	xid = get_xid();  	full_path = build_path_from_dentry(direntry);  	if (full_path == NULL) { @@ -247,27 +271,32 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,  	/* return dos attributes as pseudo xattr */  	/* return alt name if available as pseudo attr */  	if (ea_name == NULL) { -		cFYI(1, "Null xattr names not supported"); -	} else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) == 0) { +		cifs_dbg(FYI, "Null xattr names not supported\n"); +	} else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) +		   == 0) {  		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)  			goto get_ea_exit;  		if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0) { -			cFYI(1, "attempt to query cifs inode metadata"); +			cifs_dbg(FYI, "attempt to query cifs inode metadata\n");  			/* revalidate/getattr then populate from inode */  		} /* BB add else when above is implemented */ -		ea_name += 5; /* skip past user. prefix */ -		rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value, -			buf_size, cifs_sb->local_nls, -			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); -	} else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) { +		ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */ +		if (pTcon->ses->server->ops->query_all_EAs) +			rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, +				full_path, ea_name, ea_value, buf_size, +				cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & +					CIFS_MOUNT_MAP_SPECIAL_CHR); +	} else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) {  		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)  			goto get_ea_exit; -		ea_name += 4; /* skip past os2. prefix */ -		rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value, -			buf_size, cifs_sb->local_nls, -			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); +		ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */ +		if (pTcon->ses->server->ops->query_all_EAs) +			rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, +				full_path, ea_name, ea_value, buf_size, +				cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & +					CIFS_MOUNT_MAP_SPECIAL_CHR);  	} else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,  			  strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {  #ifdef CONFIG_CIFS_POSIX @@ -277,29 +306,8 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,  				cifs_sb->local_nls,  				cifs_sb->mnt_cifs_flags &  					CIFS_MOUNT_MAP_SPECIAL_CHR); -#ifdef CONFIG_CIFS_EXPERIMENTAL -		else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { -			__u16 fid; -			int oplock = 0; -			struct cifs_ntsd *pacl = NULL; -			__u32 buflen = 0; -			if (experimEnabled) -				rc = CIFSSMBOpen(xid, pTcon, full_path, -					FILE_OPEN, GENERIC_READ, 0, &fid, -					&oplock, NULL, cifs_sb->local_nls, -					cifs_sb->mnt_cifs_flags & -					CIFS_MOUNT_MAP_SPECIAL_CHR); -			/* else rc is EOPNOTSUPP from above */ - -			if (rc == 0) { -				rc = CIFSSMBGetCIFSACL(xid, pTcon, fid, &pacl, -						      &buflen); -				CIFSSMBClose(xid, pTcon, fid); -			} -		} -#endif /* EXPERIMENTAL */  #else -		cFYI(1, "query POSIX ACL not supported yet"); +		cifs_dbg(FYI, "Query POSIX ACL not supported yet\n");  #endif /* CONFIG_CIFS_POSIX */  	} else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,  			  strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { @@ -311,18 +319,46 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,  				cifs_sb->mnt_cifs_flags &  					CIFS_MOUNT_MAP_SPECIAL_CHR);  #else -		cFYI(1, "query POSIX default ACL not supported yet"); -#endif +		cifs_dbg(FYI, "Query POSIX default ACL not supported yet\n"); +#endif /* CONFIG_CIFS_POSIX */ +	} else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL, +				strlen(CIFS_XATTR_CIFS_ACL)) == 0) { +#ifdef CONFIG_CIFS_ACL +			u32 acllen; +			struct cifs_ntsd *pacl; + +			if (pTcon->ses->server->ops->get_acl == NULL) +				goto get_ea_exit; /* rc already EOPNOTSUPP */ + +			pacl = pTcon->ses->server->ops->get_acl(cifs_sb, +					direntry->d_inode, full_path, &acllen); +			if (IS_ERR(pacl)) { +				rc = PTR_ERR(pacl); +				cifs_dbg(VFS, "%s: error %zd getting sec desc\n", +					 __func__, rc); +			} else { +				if (ea_value) { +					if (acllen > buf_size) +						acllen = -ERANGE; +					else +						memcpy(ea_value, pacl, acllen); +				} +				rc = acllen; +				kfree(pacl); +			} +#else +			cifs_dbg(FYI, "Query CIFS ACL not supported yet\n"); +#endif /* CONFIG_CIFS_ACL */  	} else if (strncmp(ea_name, -		  CIFS_XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) { -		cFYI(1, "Trusted xattr namespace not supported yet"); +		  XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) { +		cifs_dbg(FYI, "Trusted xattr namespace not supported yet\n");  	} else if (strncmp(ea_name, -		  CIFS_XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) == 0) { -		cFYI(1, "Security xattr namespace not supported yet"); +		  XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) == 0) { +		cifs_dbg(FYI, "Security xattr namespace not supported yet\n");  	} else -		cFYI(1, -		    "illegal xattr request %s (only user namespace supported)", -		     ea_name); +		cifs_dbg(FYI, +			 "illegal xattr request %s (only user namespace supported)\n", +			 ea_name);  	/* We could add an additional check for streams ie  	    if proc/fs/cifs/streamstoxattr is set then @@ -334,7 +370,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,  get_ea_exit:  	kfree(full_path); -	FreeXid(xid); +	free_xid(xid);  	cifs_put_tlink(tlink);  #endif  	return rc; @@ -344,10 +380,10 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)  {  	ssize_t rc = -EOPNOTSUPP;  #ifdef CONFIG_CIFS_XATTR -	int xid; +	unsigned int xid;  	struct cifs_sb_info *cifs_sb;  	struct tcon_link *tlink; -	struct cifsTconInfo *pTcon; +	struct cifs_tcon *pTcon;  	struct super_block *sb;  	char *full_path; @@ -368,7 +404,7 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)  		return PTR_ERR(tlink);  	pTcon = tlink_tcon(tlink); -	xid = GetXid(); +	xid = get_xid();  	full_path = build_path_from_dentry(direntry);  	if (full_path == NULL) { @@ -381,14 +417,15 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)  	/* if proc/fs/cifs/streamstoxattr is set then  		search server for EAs or streams to  		returns as xattrs */ -	rc = CIFSSMBQAllEAs(xid, pTcon, full_path, NULL, data, -				buf_size, cifs_sb->local_nls, -				cifs_sb->mnt_cifs_flags & -					CIFS_MOUNT_MAP_SPECIAL_CHR); +	if (pTcon->ses->server->ops->query_all_EAs) +		rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, +				full_path, NULL, data, buf_size, +				cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & +					CIFS_MOUNT_MAP_SPECIAL_CHR);  list_ea_exit:  	kfree(full_path); -	FreeXid(xid); +	free_xid(xid);  	cifs_put_tlink(tlink);  #endif  	return rc;  | 
