xref: /kernel/linux/linux-5.10/fs/orangefs/acl.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * (C) 2001 Clemson University and The University of Chicago
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * See COPYING in top-level directory.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "protocol.h"
98c2ecf20Sopenharmony_ci#include "orangefs-kernel.h"
108c2ecf20Sopenharmony_ci#include "orangefs-bufmap.h"
118c2ecf20Sopenharmony_ci#include <linux/posix_acl_xattr.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistruct posix_acl *orangefs_get_acl(struct inode *inode, int type)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	struct posix_acl *acl;
168c2ecf20Sopenharmony_ci	int ret;
178c2ecf20Sopenharmony_ci	char *key = NULL, *value = NULL;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	switch (type) {
208c2ecf20Sopenharmony_ci	case ACL_TYPE_ACCESS:
218c2ecf20Sopenharmony_ci		key = XATTR_NAME_POSIX_ACL_ACCESS;
228c2ecf20Sopenharmony_ci		break;
238c2ecf20Sopenharmony_ci	case ACL_TYPE_DEFAULT:
248c2ecf20Sopenharmony_ci		key = XATTR_NAME_POSIX_ACL_DEFAULT;
258c2ecf20Sopenharmony_ci		break;
268c2ecf20Sopenharmony_ci	default:
278c2ecf20Sopenharmony_ci		gossip_err("orangefs_get_acl: bogus value of type %d\n", type);
288c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
298c2ecf20Sopenharmony_ci	}
308c2ecf20Sopenharmony_ci	/*
318c2ecf20Sopenharmony_ci	 * Rather than incurring a network call just to determine the exact
328c2ecf20Sopenharmony_ci	 * length of the attribute, I just allocate a max length to save on
338c2ecf20Sopenharmony_ci	 * the network call. Conceivably, we could pass NULL to
348c2ecf20Sopenharmony_ci	 * orangefs_inode_getxattr() to probe the length of the value, but
358c2ecf20Sopenharmony_ci	 * I don't do that for now.
368c2ecf20Sopenharmony_ci	 */
378c2ecf20Sopenharmony_ci	value = kmalloc(ORANGEFS_MAX_XATTR_VALUELEN, GFP_KERNEL);
388c2ecf20Sopenharmony_ci	if (!value)
398c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	gossip_debug(GOSSIP_ACL_DEBUG,
428c2ecf20Sopenharmony_ci		     "inode %pU, key %s, type %d\n",
438c2ecf20Sopenharmony_ci		     get_khandle_from_ino(inode),
448c2ecf20Sopenharmony_ci		     key,
458c2ecf20Sopenharmony_ci		     type);
468c2ecf20Sopenharmony_ci	ret = orangefs_inode_getxattr(inode, key, value,
478c2ecf20Sopenharmony_ci				      ORANGEFS_MAX_XATTR_VALUELEN);
488c2ecf20Sopenharmony_ci	/* if the key exists, convert it to an in-memory rep */
498c2ecf20Sopenharmony_ci	if (ret > 0) {
508c2ecf20Sopenharmony_ci		acl = posix_acl_from_xattr(&init_user_ns, value, ret);
518c2ecf20Sopenharmony_ci	} else if (ret == -ENODATA || ret == -ENOSYS) {
528c2ecf20Sopenharmony_ci		acl = NULL;
538c2ecf20Sopenharmony_ci	} else {
548c2ecf20Sopenharmony_ci		gossip_err("inode %pU retrieving acl's failed with error %d\n",
558c2ecf20Sopenharmony_ci			   get_khandle_from_ino(inode),
568c2ecf20Sopenharmony_ci			   ret);
578c2ecf20Sopenharmony_ci		acl = ERR_PTR(ret);
588c2ecf20Sopenharmony_ci	}
598c2ecf20Sopenharmony_ci	/* kfree(NULL) is safe, so don't worry if value ever got used */
608c2ecf20Sopenharmony_ci	kfree(value);
618c2ecf20Sopenharmony_ci	return acl;
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic int __orangefs_set_acl(struct inode *inode, struct posix_acl *acl,
658c2ecf20Sopenharmony_ci			      int type)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	int error = 0;
688c2ecf20Sopenharmony_ci	void *value = NULL;
698c2ecf20Sopenharmony_ci	size_t size = 0;
708c2ecf20Sopenharmony_ci	const char *name = NULL;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	switch (type) {
738c2ecf20Sopenharmony_ci	case ACL_TYPE_ACCESS:
748c2ecf20Sopenharmony_ci		name = XATTR_NAME_POSIX_ACL_ACCESS;
758c2ecf20Sopenharmony_ci		break;
768c2ecf20Sopenharmony_ci	case ACL_TYPE_DEFAULT:
778c2ecf20Sopenharmony_ci		name = XATTR_NAME_POSIX_ACL_DEFAULT;
788c2ecf20Sopenharmony_ci		break;
798c2ecf20Sopenharmony_ci	default:
808c2ecf20Sopenharmony_ci		gossip_err("%s: invalid type %d!\n", __func__, type);
818c2ecf20Sopenharmony_ci		return -EINVAL;
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	gossip_debug(GOSSIP_ACL_DEBUG,
858c2ecf20Sopenharmony_ci		     "%s: inode %pU, key %s type %d\n",
868c2ecf20Sopenharmony_ci		     __func__, get_khandle_from_ino(inode),
878c2ecf20Sopenharmony_ci		     name,
888c2ecf20Sopenharmony_ci		     type);
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	if (acl) {
918c2ecf20Sopenharmony_ci		size = posix_acl_xattr_size(acl->a_count);
928c2ecf20Sopenharmony_ci		value = kmalloc(size, GFP_KERNEL);
938c2ecf20Sopenharmony_ci		if (!value)
948c2ecf20Sopenharmony_ci			return -ENOMEM;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci		error = posix_acl_to_xattr(&init_user_ns, acl, value, size);
978c2ecf20Sopenharmony_ci		if (error < 0)
988c2ecf20Sopenharmony_ci			goto out;
998c2ecf20Sopenharmony_ci	}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	gossip_debug(GOSSIP_ACL_DEBUG,
1028c2ecf20Sopenharmony_ci		     "%s: name %s, value %p, size %zd, acl %p\n",
1038c2ecf20Sopenharmony_ci		     __func__, name, value, size, acl);
1048c2ecf20Sopenharmony_ci	/*
1058c2ecf20Sopenharmony_ci	 * Go ahead and set the extended attribute now. NOTE: Suppose acl
1068c2ecf20Sopenharmony_ci	 * was NULL, then value will be NULL and size will be 0 and that
1078c2ecf20Sopenharmony_ci	 * will xlate to a removexattr. However, we don't want removexattr
1088c2ecf20Sopenharmony_ci	 * complain if attributes does not exist.
1098c2ecf20Sopenharmony_ci	 */
1108c2ecf20Sopenharmony_ci	error = orangefs_inode_setxattr(inode, name, value, size, 0);
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ciout:
1138c2ecf20Sopenharmony_ci	kfree(value);
1148c2ecf20Sopenharmony_ci	if (!error)
1158c2ecf20Sopenharmony_ci		set_cached_acl(inode, type, acl);
1168c2ecf20Sopenharmony_ci	return error;
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ciint orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	int error;
1228c2ecf20Sopenharmony_ci	struct iattr iattr;
1238c2ecf20Sopenharmony_ci	int rc;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	memset(&iattr, 0, sizeof iattr);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	if (type == ACL_TYPE_ACCESS && acl) {
1288c2ecf20Sopenharmony_ci		/*
1298c2ecf20Sopenharmony_ci		 * posix_acl_update_mode checks to see if the permissions
1308c2ecf20Sopenharmony_ci		 * described by the ACL can be encoded into the
1318c2ecf20Sopenharmony_ci		 * object's mode. If so, it sets "acl" to NULL
1328c2ecf20Sopenharmony_ci		 * and "mode" to the new desired value. It is up to
1338c2ecf20Sopenharmony_ci		 * us to propagate the new mode back to the server...
1348c2ecf20Sopenharmony_ci		 */
1358c2ecf20Sopenharmony_ci		error = posix_acl_update_mode(inode, &iattr.ia_mode, &acl);
1368c2ecf20Sopenharmony_ci		if (error) {
1378c2ecf20Sopenharmony_ci			gossip_err("%s: posix_acl_update_mode err: %d\n",
1388c2ecf20Sopenharmony_ci				   __func__,
1398c2ecf20Sopenharmony_ci				   error);
1408c2ecf20Sopenharmony_ci			return error;
1418c2ecf20Sopenharmony_ci		}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci		if (inode->i_mode != iattr.ia_mode)
1448c2ecf20Sopenharmony_ci			iattr.ia_valid = ATTR_MODE;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	rc = __orangefs_set_acl(inode, acl, type);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	if (!rc && (iattr.ia_valid == ATTR_MODE))
1518c2ecf20Sopenharmony_ci		rc = __orangefs_setattr(inode, &iattr);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	return rc;
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ciint orangefs_init_acl(struct inode *inode, struct inode *dir)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	struct posix_acl *default_acl, *acl;
1598c2ecf20Sopenharmony_ci	umode_t mode = inode->i_mode;
1608c2ecf20Sopenharmony_ci	struct iattr iattr;
1618c2ecf20Sopenharmony_ci	int error = 0;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	error = posix_acl_create(dir, &mode, &default_acl, &acl);
1648c2ecf20Sopenharmony_ci	if (error)
1658c2ecf20Sopenharmony_ci		return error;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	if (default_acl) {
1688c2ecf20Sopenharmony_ci		error = __orangefs_set_acl(inode, default_acl,
1698c2ecf20Sopenharmony_ci					   ACL_TYPE_DEFAULT);
1708c2ecf20Sopenharmony_ci		posix_acl_release(default_acl);
1718c2ecf20Sopenharmony_ci	} else {
1728c2ecf20Sopenharmony_ci		inode->i_default_acl = NULL;
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	if (acl) {
1768c2ecf20Sopenharmony_ci		if (!error)
1778c2ecf20Sopenharmony_ci			error = __orangefs_set_acl(inode, acl, ACL_TYPE_ACCESS);
1788c2ecf20Sopenharmony_ci		posix_acl_release(acl);
1798c2ecf20Sopenharmony_ci	} else {
1808c2ecf20Sopenharmony_ci		inode->i_acl = NULL;
1818c2ecf20Sopenharmony_ci	}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	/* If mode of the inode was changed, then do a forcible ->setattr */
1848c2ecf20Sopenharmony_ci	if (mode != inode->i_mode) {
1858c2ecf20Sopenharmony_ci		memset(&iattr, 0, sizeof iattr);
1868c2ecf20Sopenharmony_ci		inode->i_mode = mode;
1878c2ecf20Sopenharmony_ci		iattr.ia_mode = mode;
1888c2ecf20Sopenharmony_ci		iattr.ia_valid |= ATTR_MODE;
1898c2ecf20Sopenharmony_ci		__orangefs_setattr(inode, &iattr);
1908c2ecf20Sopenharmony_ci	}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	return error;
1938c2ecf20Sopenharmony_ci}
194