1aa98d7cfSKaiGai Kohei /*-------------------------------------------------------------------------* 2aa98d7cfSKaiGai Kohei * File: fs/jffs2/acl.c 3aa98d7cfSKaiGai Kohei * POSIX ACL support on JFFS2 FileSystem 4aa98d7cfSKaiGai Kohei * 5aa98d7cfSKaiGai Kohei * Implemented by KaiGai Kohei <kaigai@ak.jp.nec.com> 6aa98d7cfSKaiGai Kohei * Copyright (C) 2006 NEC Corporation 7aa98d7cfSKaiGai Kohei * 8aa98d7cfSKaiGai Kohei * For licensing information, see the file 'LICENCE' in the jffs2 directory. 9aa98d7cfSKaiGai Kohei *-------------------------------------------------------------------------*/ 10aa98d7cfSKaiGai Kohei #include <linux/kernel.h> 11aa98d7cfSKaiGai Kohei #include <linux/slab.h> 12aa98d7cfSKaiGai Kohei #include <linux/fs.h> 13aa98d7cfSKaiGai Kohei #include <linux/time.h> 14aa98d7cfSKaiGai Kohei #include <linux/crc32.h> 15aa98d7cfSKaiGai Kohei #include <linux/jffs2.h> 16aa98d7cfSKaiGai Kohei #include <linux/xattr.h> 17aa98d7cfSKaiGai Kohei #include <linux/posix_acl_xattr.h> 18aa98d7cfSKaiGai Kohei #include <linux/mtd/mtd.h> 19aa98d7cfSKaiGai Kohei #include "nodelist.h" 20aa98d7cfSKaiGai Kohei 21aa98d7cfSKaiGai Kohei static size_t jffs2_acl_size(int count) 22aa98d7cfSKaiGai Kohei { 23aa98d7cfSKaiGai Kohei if (count <= 4) { 24de1f72faSKaiGai Kohei return sizeof(struct jffs2_acl_header) 25de1f72faSKaiGai Kohei + count * sizeof(struct jffs2_acl_entry_short); 26aa98d7cfSKaiGai Kohei } else { 27de1f72faSKaiGai Kohei return sizeof(struct jffs2_acl_header) 28de1f72faSKaiGai Kohei + 4 * sizeof(struct jffs2_acl_entry_short) 29de1f72faSKaiGai Kohei + (count - 4) * sizeof(struct jffs2_acl_entry); 30aa98d7cfSKaiGai Kohei } 31aa98d7cfSKaiGai Kohei } 32aa98d7cfSKaiGai Kohei 33aa98d7cfSKaiGai Kohei static int jffs2_acl_count(size_t size) 34aa98d7cfSKaiGai Kohei { 35aa98d7cfSKaiGai Kohei size_t s; 36aa98d7cfSKaiGai Kohei 37de1f72faSKaiGai Kohei size -= sizeof(struct jffs2_acl_header); 38de1f72faSKaiGai Kohei s = size - 4 * sizeof(struct jffs2_acl_entry_short); 39aa98d7cfSKaiGai Kohei if (s < 0) { 40de1f72faSKaiGai Kohei if (size % sizeof(struct jffs2_acl_entry_short)) 41aa98d7cfSKaiGai Kohei return -1; 42de1f72faSKaiGai Kohei return size / sizeof(struct jffs2_acl_entry_short); 43aa98d7cfSKaiGai Kohei } else { 44de1f72faSKaiGai Kohei if (s % sizeof(struct jffs2_acl_entry)) 45aa98d7cfSKaiGai Kohei return -1; 46de1f72faSKaiGai Kohei return s / sizeof(struct jffs2_acl_entry) + 4; 47aa98d7cfSKaiGai Kohei } 48aa98d7cfSKaiGai Kohei } 49aa98d7cfSKaiGai Kohei 50aa98d7cfSKaiGai Kohei static struct posix_acl *jffs2_acl_from_medium(const void *value, size_t size) 51aa98d7cfSKaiGai Kohei { 52aa98d7cfSKaiGai Kohei const char *end = (char *)value + size; 53aa98d7cfSKaiGai Kohei struct posix_acl *acl; 54aa98d7cfSKaiGai Kohei uint32_t ver; 55aa98d7cfSKaiGai Kohei int i, count; 56aa98d7cfSKaiGai Kohei 57aa98d7cfSKaiGai Kohei if (!value) 58aa98d7cfSKaiGai Kohei return NULL; 59de1f72faSKaiGai Kohei if (size < sizeof(struct jffs2_acl_header)) 60aa98d7cfSKaiGai Kohei return ERR_PTR(-EINVAL); 61de1f72faSKaiGai Kohei ver = je32_to_cpu(((struct jffs2_acl_header *)value)->a_version); 62aa98d7cfSKaiGai Kohei if (ver != JFFS2_ACL_VERSION) { 63aa98d7cfSKaiGai Kohei JFFS2_WARNING("Invalid ACL version. (=%u)\n", ver); 64aa98d7cfSKaiGai Kohei return ERR_PTR(-EINVAL); 65aa98d7cfSKaiGai Kohei } 66aa98d7cfSKaiGai Kohei 67de1f72faSKaiGai Kohei value = (char *)value + sizeof(struct jffs2_acl_header); 68aa98d7cfSKaiGai Kohei count = jffs2_acl_count(size); 69aa98d7cfSKaiGai Kohei if (count < 0) 70aa98d7cfSKaiGai Kohei return ERR_PTR(-EINVAL); 71aa98d7cfSKaiGai Kohei if (count == 0) 72aa98d7cfSKaiGai Kohei return NULL; 73aa98d7cfSKaiGai Kohei 74aa98d7cfSKaiGai Kohei acl = posix_acl_alloc(count, GFP_KERNEL); 75aa98d7cfSKaiGai Kohei if (!acl) 76aa98d7cfSKaiGai Kohei return ERR_PTR(-ENOMEM); 77aa98d7cfSKaiGai Kohei 78aa98d7cfSKaiGai Kohei for (i=0; i < count; i++) { 79de1f72faSKaiGai Kohei struct jffs2_acl_entry *entry = (struct jffs2_acl_entry *)value; 80de1f72faSKaiGai Kohei if ((char *)value + sizeof(struct jffs2_acl_entry_short) > end) 81aa98d7cfSKaiGai Kohei goto fail; 82aa98d7cfSKaiGai Kohei acl->a_entries[i].e_tag = je16_to_cpu(entry->e_tag); 83aa98d7cfSKaiGai Kohei acl->a_entries[i].e_perm = je16_to_cpu(entry->e_perm); 84aa98d7cfSKaiGai Kohei switch (acl->a_entries[i].e_tag) { 85aa98d7cfSKaiGai Kohei case ACL_USER_OBJ: 86aa98d7cfSKaiGai Kohei case ACL_GROUP_OBJ: 87aa98d7cfSKaiGai Kohei case ACL_MASK: 88aa98d7cfSKaiGai Kohei case ACL_OTHER: 89de1f72faSKaiGai Kohei value = (char *)value + sizeof(struct jffs2_acl_entry_short); 90aa98d7cfSKaiGai Kohei acl->a_entries[i].e_id = ACL_UNDEFINED_ID; 91aa98d7cfSKaiGai Kohei break; 92aa98d7cfSKaiGai Kohei 93aa98d7cfSKaiGai Kohei case ACL_USER: 94aa98d7cfSKaiGai Kohei case ACL_GROUP: 95de1f72faSKaiGai Kohei value = (char *)value + sizeof(struct jffs2_acl_entry); 96aa98d7cfSKaiGai Kohei if ((char *)value > end) 97aa98d7cfSKaiGai Kohei goto fail; 98aa98d7cfSKaiGai Kohei acl->a_entries[i].e_id = je32_to_cpu(entry->e_id); 99aa98d7cfSKaiGai Kohei break; 100aa98d7cfSKaiGai Kohei 101aa98d7cfSKaiGai Kohei default: 102aa98d7cfSKaiGai Kohei goto fail; 103aa98d7cfSKaiGai Kohei } 104aa98d7cfSKaiGai Kohei } 105aa98d7cfSKaiGai Kohei if (value != end) 106aa98d7cfSKaiGai Kohei goto fail; 107aa98d7cfSKaiGai Kohei return acl; 108aa98d7cfSKaiGai Kohei fail: 109aa98d7cfSKaiGai Kohei posix_acl_release(acl); 110aa98d7cfSKaiGai Kohei return ERR_PTR(-EINVAL); 111aa98d7cfSKaiGai Kohei } 112aa98d7cfSKaiGai Kohei 113aa98d7cfSKaiGai Kohei static void *jffs2_acl_to_medium(const struct posix_acl *acl, size_t *size) 114aa98d7cfSKaiGai Kohei { 115de1f72faSKaiGai Kohei struct jffs2_acl_header *jffs2_acl; 116aa98d7cfSKaiGai Kohei char *e; 117aa98d7cfSKaiGai Kohei size_t i; 118aa98d7cfSKaiGai Kohei 119aa98d7cfSKaiGai Kohei *size = jffs2_acl_size(acl->a_count); 120de1f72faSKaiGai Kohei jffs2_acl = kmalloc(sizeof(struct jffs2_acl_header) 121de1f72faSKaiGai Kohei + acl->a_count * sizeof(struct jffs2_acl_entry), 122aa98d7cfSKaiGai Kohei GFP_KERNEL); 123aa98d7cfSKaiGai Kohei if (!jffs2_acl) 124aa98d7cfSKaiGai Kohei return ERR_PTR(-ENOMEM); 125aa98d7cfSKaiGai Kohei jffs2_acl->a_version = cpu_to_je32(JFFS2_ACL_VERSION); 126de1f72faSKaiGai Kohei e = (char *)jffs2_acl + sizeof(struct jffs2_acl_header); 127aa98d7cfSKaiGai Kohei for (i=0; i < acl->a_count; i++) { 128de1f72faSKaiGai Kohei struct jffs2_acl_entry *entry = (struct jffs2_acl_entry *)e; 129aa98d7cfSKaiGai Kohei entry->e_tag = cpu_to_je16(acl->a_entries[i].e_tag); 130aa98d7cfSKaiGai Kohei entry->e_perm = cpu_to_je16(acl->a_entries[i].e_perm); 131aa98d7cfSKaiGai Kohei switch(acl->a_entries[i].e_tag) { 132aa98d7cfSKaiGai Kohei case ACL_USER: 133aa98d7cfSKaiGai Kohei case ACL_GROUP: 134aa98d7cfSKaiGai Kohei entry->e_id = cpu_to_je32(acl->a_entries[i].e_id); 135de1f72faSKaiGai Kohei e += sizeof(struct jffs2_acl_entry); 136aa98d7cfSKaiGai Kohei break; 137aa98d7cfSKaiGai Kohei 138aa98d7cfSKaiGai Kohei case ACL_USER_OBJ: 139aa98d7cfSKaiGai Kohei case ACL_GROUP_OBJ: 140aa98d7cfSKaiGai Kohei case ACL_MASK: 141aa98d7cfSKaiGai Kohei case ACL_OTHER: 142de1f72faSKaiGai Kohei e += sizeof(struct jffs2_acl_entry_short); 143aa98d7cfSKaiGai Kohei break; 144aa98d7cfSKaiGai Kohei 145aa98d7cfSKaiGai Kohei default: 146aa98d7cfSKaiGai Kohei goto fail; 147aa98d7cfSKaiGai Kohei } 148aa98d7cfSKaiGai Kohei } 149aa98d7cfSKaiGai Kohei return (char *)jffs2_acl; 150aa98d7cfSKaiGai Kohei fail: 151aa98d7cfSKaiGai Kohei kfree(jffs2_acl); 152aa98d7cfSKaiGai Kohei return ERR_PTR(-EINVAL); 153aa98d7cfSKaiGai Kohei } 154aa98d7cfSKaiGai Kohei 155aa98d7cfSKaiGai Kohei static struct posix_acl *jffs2_iget_acl(struct inode *inode, struct posix_acl **i_acl) 156aa98d7cfSKaiGai Kohei { 157aa98d7cfSKaiGai Kohei struct posix_acl *acl = JFFS2_ACL_NOT_CACHED; 158aa98d7cfSKaiGai Kohei 159aa98d7cfSKaiGai Kohei spin_lock(&inode->i_lock); 160aa98d7cfSKaiGai Kohei if (*i_acl != JFFS2_ACL_NOT_CACHED) 161aa98d7cfSKaiGai Kohei acl = posix_acl_dup(*i_acl); 162aa98d7cfSKaiGai Kohei spin_unlock(&inode->i_lock); 163aa98d7cfSKaiGai Kohei return acl; 164aa98d7cfSKaiGai Kohei } 165aa98d7cfSKaiGai Kohei 166aa98d7cfSKaiGai Kohei static void jffs2_iset_acl(struct inode *inode, struct posix_acl **i_acl, struct posix_acl *acl) 167aa98d7cfSKaiGai Kohei { 168aa98d7cfSKaiGai Kohei spin_lock(&inode->i_lock); 169aa98d7cfSKaiGai Kohei if (*i_acl != JFFS2_ACL_NOT_CACHED) 170aa98d7cfSKaiGai Kohei posix_acl_release(*i_acl); 171aa98d7cfSKaiGai Kohei *i_acl = posix_acl_dup(acl); 172aa98d7cfSKaiGai Kohei spin_unlock(&inode->i_lock); 173aa98d7cfSKaiGai Kohei } 174aa98d7cfSKaiGai Kohei 175aa98d7cfSKaiGai Kohei static struct posix_acl *jffs2_get_acl(struct inode *inode, int type) 176aa98d7cfSKaiGai Kohei { 177aa98d7cfSKaiGai Kohei struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); 178aa98d7cfSKaiGai Kohei struct posix_acl *acl; 179aa98d7cfSKaiGai Kohei char *value = NULL; 180aa98d7cfSKaiGai Kohei int rc, xprefix; 181aa98d7cfSKaiGai Kohei 182aa98d7cfSKaiGai Kohei switch (type) { 183aa98d7cfSKaiGai Kohei case ACL_TYPE_ACCESS: 184aa98d7cfSKaiGai Kohei acl = jffs2_iget_acl(inode, &f->i_acl_access); 185aa98d7cfSKaiGai Kohei if (acl != JFFS2_ACL_NOT_CACHED) 186aa98d7cfSKaiGai Kohei return acl; 187aa98d7cfSKaiGai Kohei xprefix = JFFS2_XPREFIX_ACL_ACCESS; 188aa98d7cfSKaiGai Kohei break; 189aa98d7cfSKaiGai Kohei case ACL_TYPE_DEFAULT: 190aa98d7cfSKaiGai Kohei acl = jffs2_iget_acl(inode, &f->i_acl_default); 191aa98d7cfSKaiGai Kohei if (acl != JFFS2_ACL_NOT_CACHED) 192aa98d7cfSKaiGai Kohei return acl; 193aa98d7cfSKaiGai Kohei xprefix = JFFS2_XPREFIX_ACL_DEFAULT; 194aa98d7cfSKaiGai Kohei break; 195aa98d7cfSKaiGai Kohei default: 196aa98d7cfSKaiGai Kohei return ERR_PTR(-EINVAL); 197aa98d7cfSKaiGai Kohei } 198aa98d7cfSKaiGai Kohei rc = do_jffs2_getxattr(inode, xprefix, "", NULL, 0); 199aa98d7cfSKaiGai Kohei if (rc > 0) { 200aa98d7cfSKaiGai Kohei value = kmalloc(rc, GFP_KERNEL); 201aa98d7cfSKaiGai Kohei if (!value) 202aa98d7cfSKaiGai Kohei return ERR_PTR(-ENOMEM); 203aa98d7cfSKaiGai Kohei rc = do_jffs2_getxattr(inode, xprefix, "", value, rc); 204aa98d7cfSKaiGai Kohei } 205aa98d7cfSKaiGai Kohei if (rc > 0) { 206aa98d7cfSKaiGai Kohei acl = jffs2_acl_from_medium(value, rc); 207aa98d7cfSKaiGai Kohei } else if (rc == -ENODATA || rc == -ENOSYS) { 208aa98d7cfSKaiGai Kohei acl = NULL; 209aa98d7cfSKaiGai Kohei } else { 210aa98d7cfSKaiGai Kohei acl = ERR_PTR(rc); 211aa98d7cfSKaiGai Kohei } 212aa98d7cfSKaiGai Kohei if (value) 213aa98d7cfSKaiGai Kohei kfree(value); 214aa98d7cfSKaiGai Kohei if (!IS_ERR(acl)) { 215aa98d7cfSKaiGai Kohei switch (type) { 216aa98d7cfSKaiGai Kohei case ACL_TYPE_ACCESS: 217aa98d7cfSKaiGai Kohei jffs2_iset_acl(inode, &f->i_acl_access, acl); 218aa98d7cfSKaiGai Kohei break; 219aa98d7cfSKaiGai Kohei case ACL_TYPE_DEFAULT: 220aa98d7cfSKaiGai Kohei jffs2_iset_acl(inode, &f->i_acl_default, acl); 221aa98d7cfSKaiGai Kohei break; 222aa98d7cfSKaiGai Kohei } 223aa98d7cfSKaiGai Kohei } 224aa98d7cfSKaiGai Kohei return acl; 225aa98d7cfSKaiGai Kohei } 226aa98d7cfSKaiGai Kohei 227aa98d7cfSKaiGai Kohei static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) 228aa98d7cfSKaiGai Kohei { 229aa98d7cfSKaiGai Kohei struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); 230aa98d7cfSKaiGai Kohei size_t size = 0; 231aa98d7cfSKaiGai Kohei char *value = NULL; 232aa98d7cfSKaiGai Kohei int rc, xprefix; 233aa98d7cfSKaiGai Kohei 234aa98d7cfSKaiGai Kohei if (S_ISLNK(inode->i_mode)) 235aa98d7cfSKaiGai Kohei return -EOPNOTSUPP; 236aa98d7cfSKaiGai Kohei 237aa98d7cfSKaiGai Kohei switch (type) { 238aa98d7cfSKaiGai Kohei case ACL_TYPE_ACCESS: 239aa98d7cfSKaiGai Kohei xprefix = JFFS2_XPREFIX_ACL_ACCESS; 240aa98d7cfSKaiGai Kohei if (acl) { 241aa98d7cfSKaiGai Kohei mode_t mode = inode->i_mode; 242aa98d7cfSKaiGai Kohei rc = posix_acl_equiv_mode(acl, &mode); 243aa98d7cfSKaiGai Kohei if (rc < 0) 244aa98d7cfSKaiGai Kohei return rc; 245aa98d7cfSKaiGai Kohei if (inode->i_mode != mode) { 246aa98d7cfSKaiGai Kohei inode->i_mode = mode; 247aa98d7cfSKaiGai Kohei jffs2_dirty_inode(inode); 248aa98d7cfSKaiGai Kohei } 249aa98d7cfSKaiGai Kohei if (rc == 0) 250aa98d7cfSKaiGai Kohei acl = NULL; 251aa98d7cfSKaiGai Kohei } 252aa98d7cfSKaiGai Kohei break; 253aa98d7cfSKaiGai Kohei case ACL_TYPE_DEFAULT: 254aa98d7cfSKaiGai Kohei xprefix = JFFS2_XPREFIX_ACL_DEFAULT; 255aa98d7cfSKaiGai Kohei if (!S_ISDIR(inode->i_mode)) 256aa98d7cfSKaiGai Kohei return acl ? -EACCES : 0; 257aa98d7cfSKaiGai Kohei break; 258aa98d7cfSKaiGai Kohei default: 259aa98d7cfSKaiGai Kohei return -EINVAL; 260aa98d7cfSKaiGai Kohei } 261aa98d7cfSKaiGai Kohei if (acl) { 262aa98d7cfSKaiGai Kohei value = jffs2_acl_to_medium(acl, &size); 263aa98d7cfSKaiGai Kohei if (IS_ERR(value)) 264aa98d7cfSKaiGai Kohei return PTR_ERR(value); 265aa98d7cfSKaiGai Kohei } 266aa98d7cfSKaiGai Kohei 267aa98d7cfSKaiGai Kohei rc = do_jffs2_setxattr(inode, xprefix, "", value, size, 0); 268aa98d7cfSKaiGai Kohei if (value) 269aa98d7cfSKaiGai Kohei kfree(value); 270aa98d7cfSKaiGai Kohei if (!rc) { 271aa98d7cfSKaiGai Kohei switch(type) { 272aa98d7cfSKaiGai Kohei case ACL_TYPE_ACCESS: 273aa98d7cfSKaiGai Kohei jffs2_iset_acl(inode, &f->i_acl_access, acl); 274aa98d7cfSKaiGai Kohei break; 275aa98d7cfSKaiGai Kohei case ACL_TYPE_DEFAULT: 276aa98d7cfSKaiGai Kohei jffs2_iset_acl(inode, &f->i_acl_default, acl); 277aa98d7cfSKaiGai Kohei break; 278aa98d7cfSKaiGai Kohei } 279aa98d7cfSKaiGai Kohei } 280aa98d7cfSKaiGai Kohei return rc; 281aa98d7cfSKaiGai Kohei } 282aa98d7cfSKaiGai Kohei 283aa98d7cfSKaiGai Kohei static int jffs2_check_acl(struct inode *inode, int mask) 284aa98d7cfSKaiGai Kohei { 285aa98d7cfSKaiGai Kohei struct posix_acl *acl; 286aa98d7cfSKaiGai Kohei int rc; 287aa98d7cfSKaiGai Kohei 288aa98d7cfSKaiGai Kohei acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS); 289aa98d7cfSKaiGai Kohei if (IS_ERR(acl)) 290aa98d7cfSKaiGai Kohei return PTR_ERR(acl); 291aa98d7cfSKaiGai Kohei if (acl) { 292aa98d7cfSKaiGai Kohei rc = posix_acl_permission(inode, acl, mask); 293aa98d7cfSKaiGai Kohei posix_acl_release(acl); 294aa98d7cfSKaiGai Kohei return rc; 295aa98d7cfSKaiGai Kohei } 296aa98d7cfSKaiGai Kohei return -EAGAIN; 297aa98d7cfSKaiGai Kohei } 298aa98d7cfSKaiGai Kohei 299aa98d7cfSKaiGai Kohei int jffs2_permission(struct inode *inode, int mask, struct nameidata *nd) 300aa98d7cfSKaiGai Kohei { 301aa98d7cfSKaiGai Kohei return generic_permission(inode, mask, jffs2_check_acl); 302aa98d7cfSKaiGai Kohei } 303aa98d7cfSKaiGai Kohei 304aa98d7cfSKaiGai Kohei int jffs2_init_acl(struct inode *inode, struct inode *dir) 305aa98d7cfSKaiGai Kohei { 306aa98d7cfSKaiGai Kohei struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); 307aa98d7cfSKaiGai Kohei struct posix_acl *acl = NULL, *clone; 308aa98d7cfSKaiGai Kohei mode_t mode; 309aa98d7cfSKaiGai Kohei int rc = 0; 310aa98d7cfSKaiGai Kohei 311aa98d7cfSKaiGai Kohei f->i_acl_access = JFFS2_ACL_NOT_CACHED; 312aa98d7cfSKaiGai Kohei f->i_acl_default = JFFS2_ACL_NOT_CACHED; 313aa98d7cfSKaiGai Kohei if (!S_ISLNK(inode->i_mode)) { 314aa98d7cfSKaiGai Kohei acl = jffs2_get_acl(dir, ACL_TYPE_DEFAULT); 315aa98d7cfSKaiGai Kohei if (IS_ERR(acl)) 316aa98d7cfSKaiGai Kohei return PTR_ERR(acl); 317aa98d7cfSKaiGai Kohei if (!acl) 318aa98d7cfSKaiGai Kohei inode->i_mode &= ~current->fs->umask; 319aa98d7cfSKaiGai Kohei } 320aa98d7cfSKaiGai Kohei if (acl) { 321aa98d7cfSKaiGai Kohei if (S_ISDIR(inode->i_mode)) { 322aa98d7cfSKaiGai Kohei rc = jffs2_set_acl(inode, ACL_TYPE_DEFAULT, acl); 323aa98d7cfSKaiGai Kohei if (rc) 324aa98d7cfSKaiGai Kohei goto cleanup; 325aa98d7cfSKaiGai Kohei } 326aa98d7cfSKaiGai Kohei clone = posix_acl_clone(acl, GFP_KERNEL); 327aa98d7cfSKaiGai Kohei rc = -ENOMEM; 328aa98d7cfSKaiGai Kohei if (!clone) 329aa98d7cfSKaiGai Kohei goto cleanup; 330aa98d7cfSKaiGai Kohei mode = inode->i_mode; 331aa98d7cfSKaiGai Kohei rc = posix_acl_create_masq(clone, &mode); 332aa98d7cfSKaiGai Kohei if (rc >= 0) { 333aa98d7cfSKaiGai Kohei inode->i_mode = mode; 334aa98d7cfSKaiGai Kohei if (rc > 0) 335aa98d7cfSKaiGai Kohei rc = jffs2_set_acl(inode, ACL_TYPE_ACCESS, clone); 336aa98d7cfSKaiGai Kohei } 337aa98d7cfSKaiGai Kohei posix_acl_release(clone); 338aa98d7cfSKaiGai Kohei } 339aa98d7cfSKaiGai Kohei cleanup: 340aa98d7cfSKaiGai Kohei posix_acl_release(acl); 341aa98d7cfSKaiGai Kohei return rc; 342aa98d7cfSKaiGai Kohei } 343aa98d7cfSKaiGai Kohei 344aa98d7cfSKaiGai Kohei void jffs2_clear_acl(struct inode *inode) 345aa98d7cfSKaiGai Kohei { 346aa98d7cfSKaiGai Kohei struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); 347aa98d7cfSKaiGai Kohei 348aa98d7cfSKaiGai Kohei if (f->i_acl_access && f->i_acl_access != JFFS2_ACL_NOT_CACHED) { 349aa98d7cfSKaiGai Kohei posix_acl_release(f->i_acl_access); 350aa98d7cfSKaiGai Kohei f->i_acl_access = JFFS2_ACL_NOT_CACHED; 351aa98d7cfSKaiGai Kohei } 352aa98d7cfSKaiGai Kohei if (f->i_acl_default && f->i_acl_default != JFFS2_ACL_NOT_CACHED) { 353aa98d7cfSKaiGai Kohei posix_acl_release(f->i_acl_default); 354aa98d7cfSKaiGai Kohei f->i_acl_default = JFFS2_ACL_NOT_CACHED; 355aa98d7cfSKaiGai Kohei } 356aa98d7cfSKaiGai Kohei } 357aa98d7cfSKaiGai Kohei 358aa98d7cfSKaiGai Kohei int jffs2_acl_chmod(struct inode *inode) 359aa98d7cfSKaiGai Kohei { 360aa98d7cfSKaiGai Kohei struct posix_acl *acl, *clone; 361aa98d7cfSKaiGai Kohei int rc; 362aa98d7cfSKaiGai Kohei 363aa98d7cfSKaiGai Kohei if (S_ISLNK(inode->i_mode)) 364aa98d7cfSKaiGai Kohei return -EOPNOTSUPP; 365aa98d7cfSKaiGai Kohei acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS); 366aa98d7cfSKaiGai Kohei if (IS_ERR(acl) || !acl) 367aa98d7cfSKaiGai Kohei return PTR_ERR(acl); 368aa98d7cfSKaiGai Kohei clone = posix_acl_clone(acl, GFP_KERNEL); 369aa98d7cfSKaiGai Kohei posix_acl_release(acl); 370aa98d7cfSKaiGai Kohei if (!clone) 371aa98d7cfSKaiGai Kohei return -ENOMEM; 372aa98d7cfSKaiGai Kohei rc = posix_acl_chmod_masq(clone, inode->i_mode); 373aa98d7cfSKaiGai Kohei if (!rc) 374aa98d7cfSKaiGai Kohei rc = jffs2_set_acl(inode, ACL_TYPE_ACCESS, clone); 375aa98d7cfSKaiGai Kohei posix_acl_release(clone); 376aa98d7cfSKaiGai Kohei return rc; 377aa98d7cfSKaiGai Kohei } 378aa98d7cfSKaiGai Kohei 379aa98d7cfSKaiGai Kohei static size_t jffs2_acl_access_listxattr(struct inode *inode, char *list, size_t list_size, 380aa98d7cfSKaiGai Kohei const char *name, size_t name_len) 381aa98d7cfSKaiGai Kohei { 382aa98d7cfSKaiGai Kohei const int retlen = sizeof(POSIX_ACL_XATTR_ACCESS); 383aa98d7cfSKaiGai Kohei 384aa98d7cfSKaiGai Kohei if (list && retlen <= list_size) 385aa98d7cfSKaiGai Kohei strcpy(list, POSIX_ACL_XATTR_ACCESS); 386aa98d7cfSKaiGai Kohei return retlen; 387aa98d7cfSKaiGai Kohei } 388aa98d7cfSKaiGai Kohei 389aa98d7cfSKaiGai Kohei static size_t jffs2_acl_default_listxattr(struct inode *inode, char *list, size_t list_size, 390aa98d7cfSKaiGai Kohei const char *name, size_t name_len) 391aa98d7cfSKaiGai Kohei { 392aa98d7cfSKaiGai Kohei const int retlen = sizeof(POSIX_ACL_XATTR_DEFAULT); 393aa98d7cfSKaiGai Kohei 394aa98d7cfSKaiGai Kohei if (list && retlen <= list_size) 395aa98d7cfSKaiGai Kohei strcpy(list, POSIX_ACL_XATTR_DEFAULT); 396aa98d7cfSKaiGai Kohei return retlen; 397aa98d7cfSKaiGai Kohei } 398aa98d7cfSKaiGai Kohei 399aa98d7cfSKaiGai Kohei static int jffs2_acl_getxattr(struct inode *inode, int type, void *buffer, size_t size) 400aa98d7cfSKaiGai Kohei { 401aa98d7cfSKaiGai Kohei struct posix_acl *acl; 402aa98d7cfSKaiGai Kohei int rc; 403aa98d7cfSKaiGai Kohei 404aa98d7cfSKaiGai Kohei acl = jffs2_get_acl(inode, type); 405aa98d7cfSKaiGai Kohei if (IS_ERR(acl)) 406aa98d7cfSKaiGai Kohei return PTR_ERR(acl); 407aa98d7cfSKaiGai Kohei if (!acl) 408aa98d7cfSKaiGai Kohei return -ENODATA; 409aa98d7cfSKaiGai Kohei rc = posix_acl_to_xattr(acl, buffer, size); 410aa98d7cfSKaiGai Kohei posix_acl_release(acl); 411aa98d7cfSKaiGai Kohei 412aa98d7cfSKaiGai Kohei return rc; 413aa98d7cfSKaiGai Kohei } 414aa98d7cfSKaiGai Kohei 415aa98d7cfSKaiGai Kohei static int jffs2_acl_access_getxattr(struct inode *inode, const char *name, void *buffer, size_t size) 416aa98d7cfSKaiGai Kohei { 417aa98d7cfSKaiGai Kohei if (name[0] != '\0') 418aa98d7cfSKaiGai Kohei return -EINVAL; 419aa98d7cfSKaiGai Kohei return jffs2_acl_getxattr(inode, ACL_TYPE_ACCESS, buffer, size); 420aa98d7cfSKaiGai Kohei } 421aa98d7cfSKaiGai Kohei 422aa98d7cfSKaiGai Kohei static int jffs2_acl_default_getxattr(struct inode *inode, const char *name, void *buffer, size_t size) 423aa98d7cfSKaiGai Kohei { 424aa98d7cfSKaiGai Kohei if (name[0] != '\0') 425aa98d7cfSKaiGai Kohei return -EINVAL; 426aa98d7cfSKaiGai Kohei return jffs2_acl_getxattr(inode, ACL_TYPE_DEFAULT, buffer, size); 427aa98d7cfSKaiGai Kohei } 428aa98d7cfSKaiGai Kohei 429aa98d7cfSKaiGai Kohei static int jffs2_acl_setxattr(struct inode *inode, int type, const void *value, size_t size) 430aa98d7cfSKaiGai Kohei { 431aa98d7cfSKaiGai Kohei struct posix_acl *acl; 432aa98d7cfSKaiGai Kohei int rc; 433aa98d7cfSKaiGai Kohei 434aa98d7cfSKaiGai Kohei if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 435aa98d7cfSKaiGai Kohei return -EPERM; 436aa98d7cfSKaiGai Kohei 437aa98d7cfSKaiGai Kohei if (value) { 438aa98d7cfSKaiGai Kohei acl = posix_acl_from_xattr(value, size); 439aa98d7cfSKaiGai Kohei if (IS_ERR(acl)) 440aa98d7cfSKaiGai Kohei return PTR_ERR(acl); 441aa98d7cfSKaiGai Kohei if (acl) { 442aa98d7cfSKaiGai Kohei rc = posix_acl_valid(acl); 443aa98d7cfSKaiGai Kohei if (rc) 444aa98d7cfSKaiGai Kohei goto out; 445aa98d7cfSKaiGai Kohei } 446aa98d7cfSKaiGai Kohei } else { 447aa98d7cfSKaiGai Kohei acl = NULL; 448aa98d7cfSKaiGai Kohei } 449aa98d7cfSKaiGai Kohei rc = jffs2_set_acl(inode, type, acl); 450aa98d7cfSKaiGai Kohei out: 451aa98d7cfSKaiGai Kohei posix_acl_release(acl); 452aa98d7cfSKaiGai Kohei return rc; 453aa98d7cfSKaiGai Kohei } 454aa98d7cfSKaiGai Kohei 455aa98d7cfSKaiGai Kohei static int jffs2_acl_access_setxattr(struct inode *inode, const char *name, 456aa98d7cfSKaiGai Kohei const void *buffer, size_t size, int flags) 457aa98d7cfSKaiGai Kohei { 458aa98d7cfSKaiGai Kohei if (name[0] != '\0') 459aa98d7cfSKaiGai Kohei return -EINVAL; 460aa98d7cfSKaiGai Kohei return jffs2_acl_setxattr(inode, ACL_TYPE_ACCESS, buffer, size); 461aa98d7cfSKaiGai Kohei } 462aa98d7cfSKaiGai Kohei 463aa98d7cfSKaiGai Kohei static int jffs2_acl_default_setxattr(struct inode *inode, const char *name, 464aa98d7cfSKaiGai Kohei const void *buffer, size_t size, int flags) 465aa98d7cfSKaiGai Kohei { 466aa98d7cfSKaiGai Kohei if (name[0] != '\0') 467aa98d7cfSKaiGai Kohei return -EINVAL; 468aa98d7cfSKaiGai Kohei return jffs2_acl_setxattr(inode, ACL_TYPE_DEFAULT, buffer, size); 469aa98d7cfSKaiGai Kohei } 470aa98d7cfSKaiGai Kohei 471aa98d7cfSKaiGai Kohei struct xattr_handler jffs2_acl_access_xattr_handler = { 472aa98d7cfSKaiGai Kohei .prefix = POSIX_ACL_XATTR_ACCESS, 473aa98d7cfSKaiGai Kohei .list = jffs2_acl_access_listxattr, 474aa98d7cfSKaiGai Kohei .get = jffs2_acl_access_getxattr, 475aa98d7cfSKaiGai Kohei .set = jffs2_acl_access_setxattr, 476aa98d7cfSKaiGai Kohei }; 477aa98d7cfSKaiGai Kohei 478aa98d7cfSKaiGai Kohei struct xattr_handler jffs2_acl_default_xattr_handler = { 479aa98d7cfSKaiGai Kohei .prefix = POSIX_ACL_XATTR_DEFAULT, 480aa98d7cfSKaiGai Kohei .list = jffs2_acl_default_listxattr, 481aa98d7cfSKaiGai Kohei .get = jffs2_acl_default_getxattr, 482aa98d7cfSKaiGai Kohei .set = jffs2_acl_default_setxattr, 483aa98d7cfSKaiGai Kohei }; 484