1*7221fe4cSGuangliang Zhao /* 2*7221fe4cSGuangliang Zhao * linux/fs/ceph/acl.c 3*7221fe4cSGuangliang Zhao * 4*7221fe4cSGuangliang Zhao * Copyright (C) 2013 Guangliang Zhao, <lucienchao@gmail.com> 5*7221fe4cSGuangliang Zhao * 6*7221fe4cSGuangliang Zhao * This program is free software; you can redistribute it and/or 7*7221fe4cSGuangliang Zhao * modify it under the terms of the GNU General Public 8*7221fe4cSGuangliang Zhao * License v2 as published by the Free Software Foundation. 9*7221fe4cSGuangliang Zhao * 10*7221fe4cSGuangliang Zhao * This program is distributed in the hope that it will be useful, 11*7221fe4cSGuangliang Zhao * but WITHOUT ANY WARRANTY; without even the implied warranty of 12*7221fe4cSGuangliang Zhao * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13*7221fe4cSGuangliang Zhao * General Public License for more details. 14*7221fe4cSGuangliang Zhao * 15*7221fe4cSGuangliang Zhao * You should have received a copy of the GNU General Public 16*7221fe4cSGuangliang Zhao * License along with this program; if not, write to the 17*7221fe4cSGuangliang Zhao * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18*7221fe4cSGuangliang Zhao * Boston, MA 021110-1307, USA. 19*7221fe4cSGuangliang Zhao */ 20*7221fe4cSGuangliang Zhao 21*7221fe4cSGuangliang Zhao #include <linux/ceph/ceph_debug.h> 22*7221fe4cSGuangliang Zhao #include <linux/fs.h> 23*7221fe4cSGuangliang Zhao #include <linux/string.h> 24*7221fe4cSGuangliang Zhao #include <linux/xattr.h> 25*7221fe4cSGuangliang Zhao #include <linux/posix_acl_xattr.h> 26*7221fe4cSGuangliang Zhao #include <linux/posix_acl.h> 27*7221fe4cSGuangliang Zhao #include <linux/sched.h> 28*7221fe4cSGuangliang Zhao #include <linux/slab.h> 29*7221fe4cSGuangliang Zhao 30*7221fe4cSGuangliang Zhao #include "super.h" 31*7221fe4cSGuangliang Zhao 32*7221fe4cSGuangliang Zhao static inline void ceph_set_cached_acl(struct inode *inode, 33*7221fe4cSGuangliang Zhao int type, struct posix_acl *acl) 34*7221fe4cSGuangliang Zhao { 35*7221fe4cSGuangliang Zhao struct ceph_inode_info *ci = ceph_inode(inode); 36*7221fe4cSGuangliang Zhao 37*7221fe4cSGuangliang Zhao spin_lock(&ci->i_ceph_lock); 38*7221fe4cSGuangliang Zhao if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0)) 39*7221fe4cSGuangliang Zhao set_cached_acl(inode, type, acl); 40*7221fe4cSGuangliang Zhao spin_unlock(&ci->i_ceph_lock); 41*7221fe4cSGuangliang Zhao } 42*7221fe4cSGuangliang Zhao 43*7221fe4cSGuangliang Zhao static inline struct posix_acl *ceph_get_cached_acl(struct inode *inode, 44*7221fe4cSGuangliang Zhao int type) 45*7221fe4cSGuangliang Zhao { 46*7221fe4cSGuangliang Zhao struct ceph_inode_info *ci = ceph_inode(inode); 47*7221fe4cSGuangliang Zhao struct posix_acl *acl = ACL_NOT_CACHED; 48*7221fe4cSGuangliang Zhao 49*7221fe4cSGuangliang Zhao spin_lock(&ci->i_ceph_lock); 50*7221fe4cSGuangliang Zhao if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0)) 51*7221fe4cSGuangliang Zhao acl = get_cached_acl(inode, type); 52*7221fe4cSGuangliang Zhao spin_unlock(&ci->i_ceph_lock); 53*7221fe4cSGuangliang Zhao 54*7221fe4cSGuangliang Zhao return acl; 55*7221fe4cSGuangliang Zhao } 56*7221fe4cSGuangliang Zhao 57*7221fe4cSGuangliang Zhao void ceph_forget_all_cached_acls(struct inode *inode) 58*7221fe4cSGuangliang Zhao { 59*7221fe4cSGuangliang Zhao forget_all_cached_acls(inode); 60*7221fe4cSGuangliang Zhao } 61*7221fe4cSGuangliang Zhao 62*7221fe4cSGuangliang Zhao struct posix_acl *ceph_get_acl(struct inode *inode, int type) 63*7221fe4cSGuangliang Zhao { 64*7221fe4cSGuangliang Zhao int size; 65*7221fe4cSGuangliang Zhao const char *name; 66*7221fe4cSGuangliang Zhao char *value = NULL; 67*7221fe4cSGuangliang Zhao struct posix_acl *acl; 68*7221fe4cSGuangliang Zhao 69*7221fe4cSGuangliang Zhao if (!IS_POSIXACL(inode)) 70*7221fe4cSGuangliang Zhao return NULL; 71*7221fe4cSGuangliang Zhao 72*7221fe4cSGuangliang Zhao acl = ceph_get_cached_acl(inode, type); 73*7221fe4cSGuangliang Zhao if (acl != ACL_NOT_CACHED) 74*7221fe4cSGuangliang Zhao return acl; 75*7221fe4cSGuangliang Zhao 76*7221fe4cSGuangliang Zhao switch (type) { 77*7221fe4cSGuangliang Zhao case ACL_TYPE_ACCESS: 78*7221fe4cSGuangliang Zhao name = POSIX_ACL_XATTR_ACCESS; 79*7221fe4cSGuangliang Zhao break; 80*7221fe4cSGuangliang Zhao case ACL_TYPE_DEFAULT: 81*7221fe4cSGuangliang Zhao name = POSIX_ACL_XATTR_DEFAULT; 82*7221fe4cSGuangliang Zhao break; 83*7221fe4cSGuangliang Zhao default: 84*7221fe4cSGuangliang Zhao BUG(); 85*7221fe4cSGuangliang Zhao } 86*7221fe4cSGuangliang Zhao 87*7221fe4cSGuangliang Zhao size = __ceph_getxattr(inode, name, "", 0); 88*7221fe4cSGuangliang Zhao if (size > 0) { 89*7221fe4cSGuangliang Zhao value = kzalloc(size, GFP_NOFS); 90*7221fe4cSGuangliang Zhao if (!value) 91*7221fe4cSGuangliang Zhao return ERR_PTR(-ENOMEM); 92*7221fe4cSGuangliang Zhao size = __ceph_getxattr(inode, name, value, size); 93*7221fe4cSGuangliang Zhao } 94*7221fe4cSGuangliang Zhao 95*7221fe4cSGuangliang Zhao if (size > 0) 96*7221fe4cSGuangliang Zhao acl = posix_acl_from_xattr(&init_user_ns, value, size); 97*7221fe4cSGuangliang Zhao else if (size == -ERANGE || size == -ENODATA || size == 0) 98*7221fe4cSGuangliang Zhao acl = NULL; 99*7221fe4cSGuangliang Zhao else 100*7221fe4cSGuangliang Zhao acl = ERR_PTR(-EIO); 101*7221fe4cSGuangliang Zhao 102*7221fe4cSGuangliang Zhao kfree(value); 103*7221fe4cSGuangliang Zhao 104*7221fe4cSGuangliang Zhao if (!IS_ERR(acl)) 105*7221fe4cSGuangliang Zhao ceph_set_cached_acl(inode, type, acl); 106*7221fe4cSGuangliang Zhao 107*7221fe4cSGuangliang Zhao return acl; 108*7221fe4cSGuangliang Zhao } 109*7221fe4cSGuangliang Zhao 110*7221fe4cSGuangliang Zhao static int ceph_set_acl(struct dentry *dentry, struct inode *inode, 111*7221fe4cSGuangliang Zhao struct posix_acl *acl, int type) 112*7221fe4cSGuangliang Zhao { 113*7221fe4cSGuangliang Zhao int ret = 0, size = 0; 114*7221fe4cSGuangliang Zhao const char *name = NULL; 115*7221fe4cSGuangliang Zhao char *value = NULL; 116*7221fe4cSGuangliang Zhao struct iattr newattrs; 117*7221fe4cSGuangliang Zhao umode_t new_mode = inode->i_mode, old_mode = inode->i_mode; 118*7221fe4cSGuangliang Zhao 119*7221fe4cSGuangliang Zhao if (acl) { 120*7221fe4cSGuangliang Zhao ret = posix_acl_valid(acl); 121*7221fe4cSGuangliang Zhao if (ret < 0) 122*7221fe4cSGuangliang Zhao goto out; 123*7221fe4cSGuangliang Zhao } 124*7221fe4cSGuangliang Zhao 125*7221fe4cSGuangliang Zhao switch (type) { 126*7221fe4cSGuangliang Zhao case ACL_TYPE_ACCESS: 127*7221fe4cSGuangliang Zhao name = POSIX_ACL_XATTR_ACCESS; 128*7221fe4cSGuangliang Zhao if (acl) { 129*7221fe4cSGuangliang Zhao ret = posix_acl_equiv_mode(acl, &new_mode); 130*7221fe4cSGuangliang Zhao if (ret < 0) 131*7221fe4cSGuangliang Zhao goto out; 132*7221fe4cSGuangliang Zhao if (ret == 0) 133*7221fe4cSGuangliang Zhao acl = NULL; 134*7221fe4cSGuangliang Zhao } 135*7221fe4cSGuangliang Zhao break; 136*7221fe4cSGuangliang Zhao case ACL_TYPE_DEFAULT: 137*7221fe4cSGuangliang Zhao if (!S_ISDIR(inode->i_mode)) { 138*7221fe4cSGuangliang Zhao ret = acl ? -EINVAL : 0; 139*7221fe4cSGuangliang Zhao goto out; 140*7221fe4cSGuangliang Zhao } 141*7221fe4cSGuangliang Zhao name = POSIX_ACL_XATTR_DEFAULT; 142*7221fe4cSGuangliang Zhao break; 143*7221fe4cSGuangliang Zhao default: 144*7221fe4cSGuangliang Zhao ret = -EINVAL; 145*7221fe4cSGuangliang Zhao goto out; 146*7221fe4cSGuangliang Zhao } 147*7221fe4cSGuangliang Zhao 148*7221fe4cSGuangliang Zhao if (acl) { 149*7221fe4cSGuangliang Zhao size = posix_acl_xattr_size(acl->a_count); 150*7221fe4cSGuangliang Zhao value = kmalloc(size, GFP_NOFS); 151*7221fe4cSGuangliang Zhao if (!value) { 152*7221fe4cSGuangliang Zhao ret = -ENOMEM; 153*7221fe4cSGuangliang Zhao goto out; 154*7221fe4cSGuangliang Zhao } 155*7221fe4cSGuangliang Zhao 156*7221fe4cSGuangliang Zhao ret = posix_acl_to_xattr(&init_user_ns, acl, value, size); 157*7221fe4cSGuangliang Zhao if (ret < 0) 158*7221fe4cSGuangliang Zhao goto out_free; 159*7221fe4cSGuangliang Zhao } 160*7221fe4cSGuangliang Zhao 161*7221fe4cSGuangliang Zhao if (new_mode != old_mode) { 162*7221fe4cSGuangliang Zhao newattrs.ia_mode = new_mode; 163*7221fe4cSGuangliang Zhao newattrs.ia_valid = ATTR_MODE; 164*7221fe4cSGuangliang Zhao ret = ceph_setattr(dentry, &newattrs); 165*7221fe4cSGuangliang Zhao if (ret) 166*7221fe4cSGuangliang Zhao goto out_free; 167*7221fe4cSGuangliang Zhao } 168*7221fe4cSGuangliang Zhao 169*7221fe4cSGuangliang Zhao if (value) 170*7221fe4cSGuangliang Zhao ret = __ceph_setxattr(dentry, name, value, size, 0); 171*7221fe4cSGuangliang Zhao else 172*7221fe4cSGuangliang Zhao ret = __ceph_removexattr(dentry, name); 173*7221fe4cSGuangliang Zhao 174*7221fe4cSGuangliang Zhao if (ret) { 175*7221fe4cSGuangliang Zhao if (new_mode != old_mode) { 176*7221fe4cSGuangliang Zhao newattrs.ia_mode = old_mode; 177*7221fe4cSGuangliang Zhao newattrs.ia_valid = ATTR_MODE; 178*7221fe4cSGuangliang Zhao ceph_setattr(dentry, &newattrs); 179*7221fe4cSGuangliang Zhao } 180*7221fe4cSGuangliang Zhao goto out_free; 181*7221fe4cSGuangliang Zhao } 182*7221fe4cSGuangliang Zhao 183*7221fe4cSGuangliang Zhao ceph_set_cached_acl(inode, type, acl); 184*7221fe4cSGuangliang Zhao 185*7221fe4cSGuangliang Zhao out_free: 186*7221fe4cSGuangliang Zhao kfree(value); 187*7221fe4cSGuangliang Zhao out: 188*7221fe4cSGuangliang Zhao return ret; 189*7221fe4cSGuangliang Zhao } 190*7221fe4cSGuangliang Zhao 191*7221fe4cSGuangliang Zhao int ceph_init_acl(struct dentry *dentry, struct inode *inode, struct inode *dir) 192*7221fe4cSGuangliang Zhao { 193*7221fe4cSGuangliang Zhao struct posix_acl *acl = NULL; 194*7221fe4cSGuangliang Zhao int ret = 0; 195*7221fe4cSGuangliang Zhao 196*7221fe4cSGuangliang Zhao if (!S_ISLNK(inode->i_mode)) { 197*7221fe4cSGuangliang Zhao if (IS_POSIXACL(dir)) { 198*7221fe4cSGuangliang Zhao acl = ceph_get_acl(dir, ACL_TYPE_DEFAULT); 199*7221fe4cSGuangliang Zhao if (IS_ERR(acl)) { 200*7221fe4cSGuangliang Zhao ret = PTR_ERR(acl); 201*7221fe4cSGuangliang Zhao goto out; 202*7221fe4cSGuangliang Zhao } 203*7221fe4cSGuangliang Zhao } 204*7221fe4cSGuangliang Zhao 205*7221fe4cSGuangliang Zhao if (!acl) 206*7221fe4cSGuangliang Zhao inode->i_mode &= ~current_umask(); 207*7221fe4cSGuangliang Zhao } 208*7221fe4cSGuangliang Zhao 209*7221fe4cSGuangliang Zhao if (IS_POSIXACL(dir) && acl) { 210*7221fe4cSGuangliang Zhao if (S_ISDIR(inode->i_mode)) { 211*7221fe4cSGuangliang Zhao ret = ceph_set_acl(dentry, inode, acl, 212*7221fe4cSGuangliang Zhao ACL_TYPE_DEFAULT); 213*7221fe4cSGuangliang Zhao if (ret) 214*7221fe4cSGuangliang Zhao goto out_release; 215*7221fe4cSGuangliang Zhao } 216*7221fe4cSGuangliang Zhao ret = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); 217*7221fe4cSGuangliang Zhao if (ret < 0) 218*7221fe4cSGuangliang Zhao goto out; 219*7221fe4cSGuangliang Zhao else if (ret > 0) 220*7221fe4cSGuangliang Zhao ret = ceph_set_acl(dentry, inode, acl, ACL_TYPE_ACCESS); 221*7221fe4cSGuangliang Zhao else 222*7221fe4cSGuangliang Zhao cache_no_acl(inode); 223*7221fe4cSGuangliang Zhao } else { 224*7221fe4cSGuangliang Zhao cache_no_acl(inode); 225*7221fe4cSGuangliang Zhao } 226*7221fe4cSGuangliang Zhao 227*7221fe4cSGuangliang Zhao out_release: 228*7221fe4cSGuangliang Zhao posix_acl_release(acl); 229*7221fe4cSGuangliang Zhao out: 230*7221fe4cSGuangliang Zhao return ret; 231*7221fe4cSGuangliang Zhao } 232*7221fe4cSGuangliang Zhao 233*7221fe4cSGuangliang Zhao int ceph_acl_chmod(struct dentry *dentry, struct inode *inode) 234*7221fe4cSGuangliang Zhao { 235*7221fe4cSGuangliang Zhao struct posix_acl *acl; 236*7221fe4cSGuangliang Zhao int ret = 0; 237*7221fe4cSGuangliang Zhao 238*7221fe4cSGuangliang Zhao if (S_ISLNK(inode->i_mode)) { 239*7221fe4cSGuangliang Zhao ret = -EOPNOTSUPP; 240*7221fe4cSGuangliang Zhao goto out; 241*7221fe4cSGuangliang Zhao } 242*7221fe4cSGuangliang Zhao 243*7221fe4cSGuangliang Zhao if (!IS_POSIXACL(inode)) 244*7221fe4cSGuangliang Zhao goto out; 245*7221fe4cSGuangliang Zhao 246*7221fe4cSGuangliang Zhao acl = ceph_get_acl(inode, ACL_TYPE_ACCESS); 247*7221fe4cSGuangliang Zhao if (IS_ERR_OR_NULL(acl)) { 248*7221fe4cSGuangliang Zhao ret = PTR_ERR(acl); 249*7221fe4cSGuangliang Zhao goto out; 250*7221fe4cSGuangliang Zhao } 251*7221fe4cSGuangliang Zhao 252*7221fe4cSGuangliang Zhao ret = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); 253*7221fe4cSGuangliang Zhao if (ret) 254*7221fe4cSGuangliang Zhao goto out; 255*7221fe4cSGuangliang Zhao ret = ceph_set_acl(dentry, inode, acl, ACL_TYPE_ACCESS); 256*7221fe4cSGuangliang Zhao posix_acl_release(acl); 257*7221fe4cSGuangliang Zhao out: 258*7221fe4cSGuangliang Zhao return ret; 259*7221fe4cSGuangliang Zhao } 260*7221fe4cSGuangliang Zhao 261*7221fe4cSGuangliang Zhao static int ceph_xattr_acl_get(struct dentry *dentry, const char *name, 262*7221fe4cSGuangliang Zhao void *value, size_t size, int type) 263*7221fe4cSGuangliang Zhao { 264*7221fe4cSGuangliang Zhao struct posix_acl *acl; 265*7221fe4cSGuangliang Zhao int ret = 0; 266*7221fe4cSGuangliang Zhao 267*7221fe4cSGuangliang Zhao if (!IS_POSIXACL(dentry->d_inode)) 268*7221fe4cSGuangliang Zhao return -EOPNOTSUPP; 269*7221fe4cSGuangliang Zhao 270*7221fe4cSGuangliang Zhao acl = ceph_get_acl(dentry->d_inode, type); 271*7221fe4cSGuangliang Zhao if (IS_ERR(acl)) 272*7221fe4cSGuangliang Zhao return PTR_ERR(acl); 273*7221fe4cSGuangliang Zhao if (acl == NULL) 274*7221fe4cSGuangliang Zhao return -ENODATA; 275*7221fe4cSGuangliang Zhao 276*7221fe4cSGuangliang Zhao ret = posix_acl_to_xattr(&init_user_ns, acl, value, size); 277*7221fe4cSGuangliang Zhao posix_acl_release(acl); 278*7221fe4cSGuangliang Zhao 279*7221fe4cSGuangliang Zhao return ret; 280*7221fe4cSGuangliang Zhao } 281*7221fe4cSGuangliang Zhao 282*7221fe4cSGuangliang Zhao static int ceph_xattr_acl_set(struct dentry *dentry, const char *name, 283*7221fe4cSGuangliang Zhao const void *value, size_t size, int flags, int type) 284*7221fe4cSGuangliang Zhao { 285*7221fe4cSGuangliang Zhao int ret = 0; 286*7221fe4cSGuangliang Zhao struct posix_acl *acl = NULL; 287*7221fe4cSGuangliang Zhao 288*7221fe4cSGuangliang Zhao if (!inode_owner_or_capable(dentry->d_inode)) { 289*7221fe4cSGuangliang Zhao ret = -EPERM; 290*7221fe4cSGuangliang Zhao goto out; 291*7221fe4cSGuangliang Zhao } 292*7221fe4cSGuangliang Zhao 293*7221fe4cSGuangliang Zhao if (!IS_POSIXACL(dentry->d_inode)) { 294*7221fe4cSGuangliang Zhao ret = -EOPNOTSUPP; 295*7221fe4cSGuangliang Zhao goto out; 296*7221fe4cSGuangliang Zhao } 297*7221fe4cSGuangliang Zhao 298*7221fe4cSGuangliang Zhao if (value) { 299*7221fe4cSGuangliang Zhao acl = posix_acl_from_xattr(&init_user_ns, value, size); 300*7221fe4cSGuangliang Zhao if (IS_ERR(acl)) { 301*7221fe4cSGuangliang Zhao ret = PTR_ERR(acl); 302*7221fe4cSGuangliang Zhao goto out; 303*7221fe4cSGuangliang Zhao } 304*7221fe4cSGuangliang Zhao 305*7221fe4cSGuangliang Zhao if (acl) { 306*7221fe4cSGuangliang Zhao ret = posix_acl_valid(acl); 307*7221fe4cSGuangliang Zhao if (ret) 308*7221fe4cSGuangliang Zhao goto out_release; 309*7221fe4cSGuangliang Zhao } 310*7221fe4cSGuangliang Zhao } 311*7221fe4cSGuangliang Zhao 312*7221fe4cSGuangliang Zhao ret = ceph_set_acl(dentry, dentry->d_inode, acl, type); 313*7221fe4cSGuangliang Zhao 314*7221fe4cSGuangliang Zhao out_release: 315*7221fe4cSGuangliang Zhao posix_acl_release(acl); 316*7221fe4cSGuangliang Zhao out: 317*7221fe4cSGuangliang Zhao return ret; 318*7221fe4cSGuangliang Zhao } 319*7221fe4cSGuangliang Zhao 320*7221fe4cSGuangliang Zhao const struct xattr_handler ceph_xattr_acl_default_handler = { 321*7221fe4cSGuangliang Zhao .prefix = POSIX_ACL_XATTR_DEFAULT, 322*7221fe4cSGuangliang Zhao .flags = ACL_TYPE_DEFAULT, 323*7221fe4cSGuangliang Zhao .get = ceph_xattr_acl_get, 324*7221fe4cSGuangliang Zhao .set = ceph_xattr_acl_set, 325*7221fe4cSGuangliang Zhao }; 326*7221fe4cSGuangliang Zhao 327*7221fe4cSGuangliang Zhao const struct xattr_handler ceph_xattr_acl_access_handler = { 328*7221fe4cSGuangliang Zhao .prefix = POSIX_ACL_XATTR_ACCESS, 329*7221fe4cSGuangliang Zhao .flags = ACL_TYPE_ACCESS, 330*7221fe4cSGuangliang Zhao .get = ceph_xattr_acl_get, 331*7221fe4cSGuangliang Zhao .set = ceph_xattr_acl_set, 332*7221fe4cSGuangliang Zhao }; 333