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