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