1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * (C) 2001 Clemson University and The University of Chicago 4 * 5 * See COPYING in top-level directory. 6 */ 7 8 #include "protocol.h" 9 #include "orangefs-kernel.h" 10 #include "orangefs-bufmap.h" 11 #include <linux/posix_acl_xattr.h> 12 13 struct posix_acl *orangefs_get_acl(struct inode *inode, int type, bool rcu) 14 { 15 struct posix_acl *acl; 16 int ret; 17 char *key = NULL, *value = NULL; 18 19 if (rcu) 20 return ERR_PTR(-ECHILD); 21 22 switch (type) { 23 case ACL_TYPE_ACCESS: 24 key = XATTR_NAME_POSIX_ACL_ACCESS; 25 break; 26 case ACL_TYPE_DEFAULT: 27 key = XATTR_NAME_POSIX_ACL_DEFAULT; 28 break; 29 default: 30 gossip_err("orangefs_get_acl: bogus value of type %d\n", type); 31 return ERR_PTR(-EINVAL); 32 } 33 /* 34 * Rather than incurring a network call just to determine the exact 35 * length of the attribute, I just allocate a max length to save on 36 * the network call. Conceivably, we could pass NULL to 37 * orangefs_inode_getxattr() to probe the length of the value, but 38 * I don't do that for now. 39 */ 40 value = kmalloc(ORANGEFS_MAX_XATTR_VALUELEN, GFP_KERNEL); 41 if (!value) 42 return ERR_PTR(-ENOMEM); 43 44 gossip_debug(GOSSIP_ACL_DEBUG, 45 "inode %pU, key %s, type %d\n", 46 get_khandle_from_ino(inode), 47 key, 48 type); 49 ret = orangefs_inode_getxattr(inode, key, value, 50 ORANGEFS_MAX_XATTR_VALUELEN); 51 /* if the key exists, convert it to an in-memory rep */ 52 if (ret > 0) { 53 acl = posix_acl_from_xattr(&init_user_ns, value, ret); 54 } else if (ret == -ENODATA || ret == -ENOSYS) { 55 acl = NULL; 56 } else { 57 gossip_err("inode %pU retrieving acl's failed with error %d\n", 58 get_khandle_from_ino(inode), 59 ret); 60 acl = ERR_PTR(ret); 61 } 62 /* kfree(NULL) is safe, so don't worry if value ever got used */ 63 kfree(value); 64 return acl; 65 } 66 67 static int __orangefs_set_acl(struct inode *inode, struct posix_acl *acl, 68 int type) 69 { 70 int error = 0; 71 void *value = NULL; 72 size_t size = 0; 73 const char *name = NULL; 74 75 switch (type) { 76 case ACL_TYPE_ACCESS: 77 name = XATTR_NAME_POSIX_ACL_ACCESS; 78 break; 79 case ACL_TYPE_DEFAULT: 80 name = XATTR_NAME_POSIX_ACL_DEFAULT; 81 break; 82 default: 83 gossip_err("%s: invalid type %d!\n", __func__, type); 84 return -EINVAL; 85 } 86 87 gossip_debug(GOSSIP_ACL_DEBUG, 88 "%s: inode %pU, key %s type %d\n", 89 __func__, get_khandle_from_ino(inode), 90 name, 91 type); 92 93 if (acl) { 94 size = posix_acl_xattr_size(acl->a_count); 95 value = kmalloc(size, GFP_KERNEL); 96 if (!value) 97 return -ENOMEM; 98 99 error = posix_acl_to_xattr(&init_user_ns, acl, value, size); 100 if (error < 0) 101 goto out; 102 } 103 104 gossip_debug(GOSSIP_ACL_DEBUG, 105 "%s: name %s, value %p, size %zd, acl %p\n", 106 __func__, name, value, size, acl); 107 /* 108 * Go ahead and set the extended attribute now. NOTE: Suppose acl 109 * was NULL, then value will be NULL and size will be 0 and that 110 * will xlate to a removexattr. However, we don't want removexattr 111 * complain if attributes does not exist. 112 */ 113 error = orangefs_inode_setxattr(inode, name, value, size, 0); 114 115 out: 116 kfree(value); 117 if (!error) 118 set_cached_acl(inode, type, acl); 119 return error; 120 } 121 122 int orangefs_set_acl(struct user_namespace *mnt_userns, struct inode *inode, 123 struct posix_acl *acl, int type) 124 { 125 int error; 126 struct iattr iattr; 127 int rc; 128 129 memset(&iattr, 0, sizeof iattr); 130 131 if (type == ACL_TYPE_ACCESS && acl) { 132 /* 133 * posix_acl_update_mode checks to see if the permissions 134 * described by the ACL can be encoded into the 135 * object's mode. If so, it sets "acl" to NULL 136 * and "mode" to the new desired value. It is up to 137 * us to propagate the new mode back to the server... 138 */ 139 error = posix_acl_update_mode(&init_user_ns, inode, 140 &iattr.ia_mode, &acl); 141 if (error) { 142 gossip_err("%s: posix_acl_update_mode err: %d\n", 143 __func__, 144 error); 145 return error; 146 } 147 148 if (inode->i_mode != iattr.ia_mode) 149 iattr.ia_valid = ATTR_MODE; 150 151 } 152 153 rc = __orangefs_set_acl(inode, acl, type); 154 155 if (!rc && (iattr.ia_valid == ATTR_MODE)) 156 rc = __orangefs_setattr(inode, &iattr); 157 158 return rc; 159 } 160 161 int orangefs_init_acl(struct inode *inode, struct inode *dir) 162 { 163 struct posix_acl *default_acl, *acl; 164 umode_t mode = inode->i_mode; 165 struct iattr iattr; 166 int error = 0; 167 168 error = posix_acl_create(dir, &mode, &default_acl, &acl); 169 if (error) 170 return error; 171 172 if (default_acl) { 173 error = __orangefs_set_acl(inode, default_acl, 174 ACL_TYPE_DEFAULT); 175 posix_acl_release(default_acl); 176 } else { 177 inode->i_default_acl = NULL; 178 } 179 180 if (acl) { 181 if (!error) 182 error = __orangefs_set_acl(inode, acl, ACL_TYPE_ACCESS); 183 posix_acl_release(acl); 184 } else { 185 inode->i_acl = NULL; 186 } 187 188 /* If mode of the inode was changed, then do a forcible ->setattr */ 189 if (mode != inode->i_mode) { 190 memset(&iattr, 0, sizeof iattr); 191 inode->i_mode = mode; 192 iattr.ia_mode = mode; 193 iattr.ia_valid |= ATTR_MODE; 194 __orangefs_setattr(inode, &iattr); 195 } 196 197 return error; 198 } 199