diff options
author | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2015-08-05 17:04:01 -0300 |
---|---|---|
committer | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2015-08-05 17:04:01 -0300 |
commit | 57f0f512b273f60d52568b8c6b77e17f5636edc0 (patch) | |
tree | 5e910f0e82173f4ef4f51111366a3f1299037a7b /drivers/staging/lustre/lustre/obdclass/acl.c |
Initial import
Diffstat (limited to 'drivers/staging/lustre/lustre/obdclass/acl.c')
-rw-r--r-- | drivers/staging/lustre/lustre/obdclass/acl.c | 548 |
1 files changed, 548 insertions, 0 deletions
diff --git a/drivers/staging/lustre/lustre/obdclass/acl.c b/drivers/staging/lustre/lustre/obdclass/acl.c new file mode 100644 index 000000000..9a69f6b35 --- /dev/null +++ b/drivers/staging/lustre/lustre/obdclass/acl.c @@ -0,0 +1,548 @@ +/* + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * GPL HEADER END + */ +/* + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Use is subject to license terms. + * + * Copyright (c) 2012, Intel Corporation. + */ +/* + * This file is part of Lustre, http://www.lustre.org/ + * Lustre is a trademark of Sun Microsystems, Inc. + * + * lustre/obdclass/acl.c + * + * Lustre Access Control List. + * + * Author: Fan Yong <fanyong@clusterfs.com> + */ + +#define DEBUG_SUBSYSTEM S_SEC +#include "../include/lu_object.h" +#include "../include/lustre_acl.h" +#include "../include/lustre_eacl.h" +#include "../include/obd_support.h" + +#ifdef CONFIG_FS_POSIX_ACL + +#define CFS_ACL_XATTR_VERSION POSIX_ACL_XATTR_VERSION + +enum { + ES_UNK = 0, /* unknown stat */ + ES_UNC = 1, /* ACL entry is not changed */ + ES_MOD = 2, /* ACL entry is modified */ + ES_ADD = 3, /* ACL entry is added */ + ES_DEL = 4 /* ACL entry is deleted */ +}; + +static inline void lustre_ext_acl_le_to_cpu(ext_acl_xattr_entry *d, + ext_acl_xattr_entry *s) +{ + d->e_tag = le16_to_cpu(s->e_tag); + d->e_perm = le16_to_cpu(s->e_perm); + d->e_id = le32_to_cpu(s->e_id); + d->e_stat = le32_to_cpu(s->e_stat); +} + +static inline void lustre_ext_acl_cpu_to_le(ext_acl_xattr_entry *d, + ext_acl_xattr_entry *s) +{ + d->e_tag = cpu_to_le16(s->e_tag); + d->e_perm = cpu_to_le16(s->e_perm); + d->e_id = cpu_to_le32(s->e_id); + d->e_stat = cpu_to_le32(s->e_stat); +} + +static inline void lustre_posix_acl_le_to_cpu(posix_acl_xattr_entry *d, + posix_acl_xattr_entry *s) +{ + d->e_tag = le16_to_cpu(s->e_tag); + d->e_perm = le16_to_cpu(s->e_perm); + d->e_id = le32_to_cpu(s->e_id); +} + +static inline void lustre_posix_acl_cpu_to_le(posix_acl_xattr_entry *d, + posix_acl_xattr_entry *s) +{ + d->e_tag = cpu_to_le16(s->e_tag); + d->e_perm = cpu_to_le16(s->e_perm); + d->e_id = cpu_to_le32(s->e_id); +} + + +/* if "new_count == 0", then "new = {a_version, NULL}", NOT NULL. */ +static int lustre_posix_acl_xattr_reduce_space(posix_acl_xattr_header **header, + int old_count, int new_count) +{ + int old_size = CFS_ACL_XATTR_SIZE(old_count, posix_acl_xattr); + int new_size = CFS_ACL_XATTR_SIZE(new_count, posix_acl_xattr); + posix_acl_xattr_header *new; + + if (unlikely(old_count <= new_count)) + return old_size; + + OBD_ALLOC(new, new_size); + if (unlikely(new == NULL)) + return -ENOMEM; + + memcpy(new, *header, new_size); + OBD_FREE(*header, old_size); + *header = new; + return new_size; +} + +/* if "new_count == 0", then "new = {0, NULL}", NOT NULL. */ +static int lustre_ext_acl_xattr_reduce_space(ext_acl_xattr_header **header, + int old_count) +{ + int ext_count = le32_to_cpu((*header)->a_count); + int ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr); + int old_size = CFS_ACL_XATTR_SIZE(old_count, ext_acl_xattr); + ext_acl_xattr_header *new; + + if (unlikely(old_count <= ext_count)) + return 0; + + OBD_ALLOC(new, ext_size); + if (unlikely(new == NULL)) + return -ENOMEM; + + memcpy(new, *header, ext_size); + OBD_FREE(*header, old_size); + *header = new; + return 0; +} + +/* + * Generate new extended ACL based on the posix ACL. + */ +ext_acl_xattr_header * +lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size) +{ + int count, i, esize; + ext_acl_xattr_header *new; + + if (unlikely(size < 0)) + return ERR_PTR(-EINVAL); + else if (!size) + count = 0; + else + count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr); + esize = CFS_ACL_XATTR_SIZE(count, ext_acl_xattr); + OBD_ALLOC(new, esize); + if (unlikely(new == NULL)) + return ERR_PTR(-ENOMEM); + + new->a_count = cpu_to_le32(count); + for (i = 0; i < count; i++) { + new->a_entries[i].e_tag = header->a_entries[i].e_tag; + new->a_entries[i].e_perm = header->a_entries[i].e_perm; + new->a_entries[i].e_id = header->a_entries[i].e_id; + new->a_entries[i].e_stat = cpu_to_le32(ES_UNK); + } + + return new; +} +EXPORT_SYMBOL(lustre_posix_acl_xattr_2ext); + +/* + * Filter out the "nobody" entries in the posix ACL. + */ +int lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, size_t size, + posix_acl_xattr_header **out) +{ + int count, i, j, rc = 0; + __u32 id; + posix_acl_xattr_header *new; + + if (!size) + return 0; + if (size < sizeof(*new)) + return -EINVAL; + + OBD_ALLOC(new, size); + if (unlikely(new == NULL)) + return -ENOMEM; + + new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION); + count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr); + for (i = 0, j = 0; i < count; i++) { + id = le32_to_cpu(header->a_entries[i].e_id); + switch (le16_to_cpu(header->a_entries[i].e_tag)) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + if (id != ACL_UNDEFINED_ID) { + rc = -EIO; + goto _out; + } + + memcpy(&new->a_entries[j++], &header->a_entries[i], + sizeof(posix_acl_xattr_entry)); + break; + case ACL_USER: + if (id != NOBODY_UID) + memcpy(&new->a_entries[j++], + &header->a_entries[i], + sizeof(posix_acl_xattr_entry)); + break; + case ACL_GROUP: + if (id != NOBODY_GID) + memcpy(&new->a_entries[j++], + &header->a_entries[i], + sizeof(posix_acl_xattr_entry)); + break; + default: + rc = -EIO; + goto _out; + } + } + + /* free unused space. */ + rc = lustre_posix_acl_xattr_reduce_space(&new, count, j); + if (rc >= 0) { + size = rc; + *out = new; + rc = 0; + } + +_out: + if (rc) { + OBD_FREE(new, size); + size = rc; + } + return size; +} +EXPORT_SYMBOL(lustre_posix_acl_xattr_filter); + +/* + * Release the posix ACL space. + */ +void lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size) +{ + OBD_FREE(header, size); +} +EXPORT_SYMBOL(lustre_posix_acl_xattr_free); + +/* + * Release the extended ACL space. + */ +void lustre_ext_acl_xattr_free(ext_acl_xattr_header *header) +{ + OBD_FREE(header, CFS_ACL_XATTR_SIZE(le32_to_cpu(header->a_count), \ + ext_acl_xattr)); +} +EXPORT_SYMBOL(lustre_ext_acl_xattr_free); + +static ext_acl_xattr_entry * +lustre_ext_acl_xattr_search(ext_acl_xattr_header *header, + posix_acl_xattr_entry *entry, int *pos) +{ + int once, start, end, i, j, count = le32_to_cpu(header->a_count); + + once = 0; + start = *pos; + end = count; + +again: + for (i = start; i < end; i++) { + if (header->a_entries[i].e_tag == entry->e_tag && + header->a_entries[i].e_id == entry->e_id) { + j = i; + if (++i >= count) + i = 0; + *pos = i; + return &header->a_entries[j]; + } + } + + if (!once) { + once = 1; + start = 0; + end = *pos; + goto again; + } + + return NULL; +} + +/* + * Merge the posix ACL and the extended ACL into new posix ACL. + */ +int lustre_acl_xattr_merge2posix(posix_acl_xattr_header *posix_header, int size, + ext_acl_xattr_header *ext_header, + posix_acl_xattr_header **out) +{ + int posix_count, posix_size, i, j; + int ext_count = le32_to_cpu(ext_header->a_count), pos = 0, rc = 0; + posix_acl_xattr_entry pe = {ACL_MASK, 0, ACL_UNDEFINED_ID}; + posix_acl_xattr_header *new; + ext_acl_xattr_entry *ee, ae; + + lustre_posix_acl_cpu_to_le(&pe, &pe); + ee = lustre_ext_acl_xattr_search(ext_header, &pe, &pos); + if (ee == NULL || le32_to_cpu(ee->e_stat) == ES_DEL) { + /* there are only base ACL entries at most. */ + posix_count = 3; + posix_size = CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr); + OBD_ALLOC(new, posix_size); + if (unlikely(new == NULL)) + return -ENOMEM; + + new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION); + for (i = 0, j = 0; i < ext_count; i++) { + lustre_ext_acl_le_to_cpu(&ae, + &ext_header->a_entries[i]); + switch (ae.e_tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_OTHER: + if (ae.e_id != ACL_UNDEFINED_ID) { + rc = -EIO; + goto _out; + } + + if (ae.e_stat != ES_DEL) { + new->a_entries[j].e_tag = + ext_header->a_entries[i].e_tag; + new->a_entries[j].e_perm = + ext_header->a_entries[i].e_perm; + new->a_entries[j++].e_id = + ext_header->a_entries[i].e_id; + } + break; + case ACL_MASK: + case ACL_USER: + case ACL_GROUP: + if (ae.e_stat == ES_DEL) + break; + default: + rc = -EIO; + goto _out; + } + } + } else { + /* maybe there are valid ACL_USER or ACL_GROUP entries in the + * original server-side ACL, they are regarded as ES_UNC stat.*/ + int ori_posix_count; + + if (unlikely(size < 0)) + return -EINVAL; + else if (!size) + ori_posix_count = 0; + else + ori_posix_count = + CFS_ACL_XATTR_COUNT(size, posix_acl_xattr); + posix_count = ori_posix_count + ext_count; + posix_size = + CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr); + OBD_ALLOC(new, posix_size); + if (unlikely(new == NULL)) + return -ENOMEM; + + new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION); + /* 1. process the unchanged ACL entries + * in the original server-side ACL. */ + pos = 0; + for (i = 0, j = 0; i < ori_posix_count; i++) { + ee = lustre_ext_acl_xattr_search(ext_header, + &posix_header->a_entries[i], &pos); + if (ee == NULL) + memcpy(&new->a_entries[j++], + &posix_header->a_entries[i], + sizeof(posix_acl_xattr_entry)); + } + + /* 2. process the non-deleted entries + * from client-side extended ACL. */ + for (i = 0; i < ext_count; i++) { + if (le16_to_cpu(ext_header->a_entries[i].e_stat) != + ES_DEL) { + new->a_entries[j].e_tag = + ext_header->a_entries[i].e_tag; + new->a_entries[j].e_perm = + ext_header->a_entries[i].e_perm; + new->a_entries[j++].e_id = + ext_header->a_entries[i].e_id; + } + } + } + + /* free unused space. */ + rc = lustre_posix_acl_xattr_reduce_space(&new, posix_count, j); + if (rc >= 0) { + posix_size = rc; + *out = new; + rc = 0; + } + +_out: + if (rc) { + OBD_FREE(new, posix_size); + posix_size = rc; + } + return posix_size; +} +EXPORT_SYMBOL(lustre_acl_xattr_merge2posix); + +/* + * Merge the posix ACL and the extended ACL into new extended ACL. + */ +ext_acl_xattr_header * +lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size, + ext_acl_xattr_header *ext_header) +{ + int ori_ext_count, posix_count, ext_count, ext_size; + int i, j, pos = 0, rc = 0; + posix_acl_xattr_entry pae; + ext_acl_xattr_header *new; + ext_acl_xattr_entry *ee, eae; + + if (unlikely(size < 0)) + return ERR_PTR(-EINVAL); + else if (!size) + posix_count = 0; + else + posix_count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr); + ori_ext_count = le32_to_cpu(ext_header->a_count); + ext_count = posix_count + ori_ext_count; + ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr); + + OBD_ALLOC(new, ext_size); + if (unlikely(new == NULL)) + return ERR_PTR(-ENOMEM); + + for (i = 0, j = 0; i < posix_count; i++) { + lustre_posix_acl_le_to_cpu(&pae, &posix_header->a_entries[i]); + switch (pae.e_tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + if (pae.e_id != ACL_UNDEFINED_ID) { + rc = -EIO; + goto out; + } + case ACL_USER: + /* ignore "nobody" entry. */ + if (pae.e_id == NOBODY_UID) + break; + + new->a_entries[j].e_tag = + posix_header->a_entries[i].e_tag; + new->a_entries[j].e_perm = + posix_header->a_entries[i].e_perm; + new->a_entries[j].e_id = + posix_header->a_entries[i].e_id; + ee = lustre_ext_acl_xattr_search(ext_header, + &posix_header->a_entries[i], &pos); + if (ee) { + if (posix_header->a_entries[i].e_perm != + ee->e_perm) + /* entry modified. */ + ee->e_stat = + new->a_entries[j++].e_stat = + cpu_to_le32(ES_MOD); + else + /* entry unchanged. */ + ee->e_stat = + new->a_entries[j++].e_stat = + cpu_to_le32(ES_UNC); + } else { + /* new entry. */ + new->a_entries[j++].e_stat = + cpu_to_le32(ES_ADD); + } + break; + case ACL_GROUP: + /* ignore "nobody" entry. */ + if (pae.e_id == NOBODY_GID) + break; + new->a_entries[j].e_tag = + posix_header->a_entries[i].e_tag; + new->a_entries[j].e_perm = + posix_header->a_entries[i].e_perm; + new->a_entries[j].e_id = + posix_header->a_entries[i].e_id; + ee = lustre_ext_acl_xattr_search(ext_header, + &posix_header->a_entries[i], &pos); + if (ee) { + if (posix_header->a_entries[i].e_perm != + ee->e_perm) + /* entry modified. */ + ee->e_stat = + new->a_entries[j++].e_stat = + cpu_to_le32(ES_MOD); + else + /* entry unchanged. */ + ee->e_stat = + new->a_entries[j++].e_stat = + cpu_to_le32(ES_UNC); + } else { + /* new entry. */ + new->a_entries[j++].e_stat = + cpu_to_le32(ES_ADD); + } + break; + default: + rc = -EIO; + goto out; + } + } + + /* process deleted entries. */ + for (i = 0; i < ori_ext_count; i++) { + lustre_ext_acl_le_to_cpu(&eae, &ext_header->a_entries[i]); + if (eae.e_stat == ES_UNK) { + /* ignore "nobody" entry. */ + if ((eae.e_tag == ACL_USER && eae.e_id == NOBODY_UID) || + (eae.e_tag == ACL_GROUP && eae.e_id == NOBODY_GID)) + continue; + + new->a_entries[j].e_tag = + ext_header->a_entries[i].e_tag; + new->a_entries[j].e_perm = + ext_header->a_entries[i].e_perm; + new->a_entries[j].e_id = ext_header->a_entries[i].e_id; + new->a_entries[j++].e_stat = cpu_to_le32(ES_DEL); + } + } + + new->a_count = cpu_to_le32(j); + /* free unused space. */ + rc = lustre_ext_acl_xattr_reduce_space(&new, ext_count); + +out: + if (rc) { + OBD_FREE(new, ext_size); + new = ERR_PTR(rc); + } + return new; +} +EXPORT_SYMBOL(lustre_acl_xattr_merge2ext); + +#endif |