diff options
author | trasz <trasz@FreeBSD.org> | 2009-06-25 12:46:59 +0000 |
---|---|---|
committer | trasz <trasz@FreeBSD.org> | 2009-06-25 12:46:59 +0000 |
commit | ff2751123334f5d80faa47567304d59aed236eba (patch) | |
tree | 2ef84b1a3d387c8edf2b81194552ad8337bd003b /lib/libc/posix1e/acl_strip.c | |
parent | 9a27798fa1cde67ed249d166ee358fee1a684179 (diff) | |
download | FreeBSD-src-ff2751123334f5d80faa47567304d59aed236eba.zip FreeBSD-src-ff2751123334f5d80faa47567304d59aed236eba.tar.gz |
Add NFSv4 ACL support to libc.
This adds the following functions to the acl(3) API: acl_add_flag_np,
acl_clear_flags_np, acl_create_entry_np, acl_delete_entry_np,
acl_delete_flag_np, acl_get_extended_np, acl_get_flag_np, acl_get_flagset_np,
acl_set_extended_np, acl_set_flagset_np, acl_to_text_np, acl_is_trivial_np,
acl_strip_np, acl_get_brand_np. Most of them are similar to what Darwin
does. There are no backward-incompatible changes.
Approved by: rwatson@
Diffstat (limited to 'lib/libc/posix1e/acl_strip.c')
-rw-r--r-- | lib/libc/posix1e/acl_strip.c | 600 |
1 files changed, 600 insertions, 0 deletions
diff --git a/lib/libc/posix1e/acl_strip.c b/lib/libc/posix1e/acl_strip.c new file mode 100644 index 0000000..0cb68e2 --- /dev/null +++ b/lib/libc/posix1e/acl_strip.c @@ -0,0 +1,600 @@ +/*- + * Copyright (c) 2001 Chris D. Faulhaber + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE VOICES IN HIS HEAD BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <errno.h> +#include <stdio.h> +#include <assert.h> +#include <sys/acl.h> + +#include "acl_support.h" + +/* + * These two routines from sys/kern/subr_acl_nfs4.c are used by both kernel + * and libc. + */ +void acl_nfs4_sync_acl_from_mode(struct acl *aclp, mode_t mode, + int file_owner_id); +void acl_nfs4_sync_mode_from_acl(mode_t *_mode, const struct acl *aclp); + +static acl_t +_nfs4_acl_strip_np(const acl_t aclp, int recalculate_mask) +{ + acl_t newacl; + mode_t mode; + + newacl = acl_init(ACL_MAX_ENTRIES); + if (newacl == NULL) { + errno = ENOMEM; + return (NULL); + } + + _acl_brand_as(newacl, ACL_BRAND_NFS4); + + acl_nfs4_sync_mode_from_acl(&mode, &(aclp->ats_acl)); + acl_nfs4_sync_acl_from_mode(&(newacl->ats_acl), mode, -1); + + return (newacl); +} + +static acl_t +_posix1e_acl_strip_np(const acl_t aclp, int recalculate_mask) +{ + acl_t acl_new, acl_old; + acl_entry_t entry, entry_new; + acl_permset_t perm; + acl_tag_t tag; + int entry_id, have_mask_entry; + + assert(_acl_brand(aclp) == ACL_BRAND_POSIX); + + acl_old = acl_dup(aclp); + if (acl_old == NULL) + return (NULL); + + assert(_acl_brand(acl_old) == ACL_BRAND_POSIX); + + have_mask_entry = 0; + acl_new = acl_init(ACL_MAX_ENTRIES); + if (acl_new == NULL) + return (NULL); + tag = ACL_UNDEFINED_TAG; + + /* only save the default user/group/other entries */ + entry_id = ACL_FIRST_ENTRY; + while (acl_get_entry(acl_old, entry_id, &entry) == 1) { + entry_id = ACL_NEXT_ENTRY; + + assert(_entry_brand(entry) == ACL_BRAND_POSIX); + + if (acl_get_tag_type(entry, &tag) == -1) + return (NULL); + + switch(tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_OTHER: + if (acl_get_tag_type(entry, &tag) == -1) + return (NULL); + if (acl_get_permset(entry, &perm) == -1) + return (NULL); + if (acl_create_entry(&acl_new, &entry_new) == -1) + return (NULL); + if (acl_set_tag_type(entry_new, tag) == -1) + return (NULL); + if (acl_set_permset(entry_new, perm) == -1) + return (NULL); + if (acl_copy_entry(entry_new, entry) == -1) + return (NULL); + assert(_entry_brand(entry_new) == ACL_BRAND_POSIX); + break; + case ACL_MASK: + have_mask_entry = 1; + break; + default: + break; + } + } + + assert(_acl_brand(acl_new) == ACL_BRAND_POSIX); + + if (have_mask_entry && recalculate_mask) { + if (acl_calc_mask(&acl_new) == -1) + return (NULL); + } + + return (acl_new); +} + +acl_t +acl_strip_np(const acl_t aclp, int recalculate_mask) +{ + switch (_acl_brand(aclp)) { + case ACL_BRAND_NFS4: + return (_nfs4_acl_strip_np(aclp, recalculate_mask)); + + case ACL_BRAND_POSIX: + return (_posix1e_acl_strip_np(aclp, recalculate_mask)); + + default: + errno = EINVAL; + return (NULL); + } +} + +/* + * Return 1, if ACL is trivial, 0 otherwise. + * + * ACL is trivial, iff its meaning could be fully expressed using just file + * mode. In other words, ACL is trivial iff it doesn't have "+" to the right + * of the mode bits in "ls -l" output ;-) + */ +int +acl_is_trivial_np(const acl_t aclp, int *trivialp) +{ + acl_t tmpacl; + int differs; + + if (aclp == NULL || trivialp == NULL) { + errno = EINVAL; + return (-1); + } + + switch (_acl_brand(aclp)) { + case ACL_BRAND_POSIX: + if (aclp->ats_acl.acl_cnt == 3) + *trivialp = 1; + else + *trivialp = 0; + + return (0); + + case ACL_BRAND_NFS4: + /* + * Calculate trivial ACL - using acl_strip_np - and compare + * with the original. + */ + tmpacl = acl_strip_np(aclp, 0); + if (tmpacl == NULL) + return (-1); + + differs = _acl_differs(aclp, tmpacl); + acl_free(tmpacl); + + if (differs) + *trivialp = 0; + else + *trivialp = 1; + + return (0); + + default: + errno = EINVAL; + return (-1); + } +} +/*- + * Copyright (c) 2001 Chris D. Faulhaber + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE VOICES IN HIS HEAD BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <errno.h> +#include <stdio.h> +#include <assert.h> +#include <sys/acl.h> + +#include "acl_support.h" + +/* + * These two routines from sys/kern/subr_acl_nfs4.c are used by both kernel + * and libc. + */ +void acl_nfs4_sync_acl_from_mode(struct acl *aclp, mode_t mode, + int file_owner_id); +void acl_nfs4_sync_mode_from_acl(mode_t *_mode, const struct acl *aclp); + +static acl_t +_nfs4_acl_strip_np(const acl_t aclp, int recalculate_mask) +{ + acl_t newacl; + mode_t mode; + + newacl = acl_init(ACL_MAX_ENTRIES); + if (newacl == NULL) { + errno = ENOMEM; + return (NULL); + } + + _acl_brand_as(newacl, ACL_BRAND_NFS4); + + acl_nfs4_sync_mode_from_acl(&mode, &(aclp->ats_acl)); + acl_nfs4_sync_acl_from_mode(&(newacl->ats_acl), mode, -1); + + return (newacl); +} + +static acl_t +_posix1e_acl_strip_np(const acl_t aclp, int recalculate_mask) +{ + acl_t acl_new, acl_old; + acl_entry_t entry, entry_new; + acl_permset_t perm; + acl_tag_t tag; + int entry_id, have_mask_entry; + + assert(_acl_brand(aclp) == ACL_BRAND_POSIX); + + acl_old = acl_dup(aclp); + if (acl_old == NULL) + return (NULL); + + assert(_acl_brand(acl_old) == ACL_BRAND_POSIX); + + have_mask_entry = 0; + acl_new = acl_init(ACL_MAX_ENTRIES); + if (acl_new == NULL) + return (NULL); + tag = ACL_UNDEFINED_TAG; + + /* only save the default user/group/other entries */ + entry_id = ACL_FIRST_ENTRY; + while (acl_get_entry(acl_old, entry_id, &entry) == 1) { + entry_id = ACL_NEXT_ENTRY; + + assert(_entry_brand(entry) == ACL_BRAND_POSIX); + + if (acl_get_tag_type(entry, &tag) == -1) + return (NULL); + + switch(tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_OTHER: + if (acl_get_tag_type(entry, &tag) == -1) + return (NULL); + if (acl_get_permset(entry, &perm) == -1) + return (NULL); + if (acl_create_entry(&acl_new, &entry_new) == -1) + return (NULL); + if (acl_set_tag_type(entry_new, tag) == -1) + return (NULL); + if (acl_set_permset(entry_new, perm) == -1) + return (NULL); + if (acl_copy_entry(entry_new, entry) == -1) + return (NULL); + assert(_entry_brand(entry_new) == ACL_BRAND_POSIX); + break; + case ACL_MASK: + have_mask_entry = 1; + break; + default: + break; + } + } + + assert(_acl_brand(acl_new) == ACL_BRAND_POSIX); + + if (have_mask_entry && recalculate_mask) { + if (acl_calc_mask(&acl_new) == -1) + return (NULL); + } + + return (acl_new); +} + +acl_t +acl_strip_np(const acl_t aclp, int recalculate_mask) +{ + switch (_acl_brand(aclp)) { + case ACL_BRAND_NFS4: + return (_nfs4_acl_strip_np(aclp, recalculate_mask)); + + case ACL_BRAND_POSIX: + return (_posix1e_acl_strip_np(aclp, recalculate_mask)); + + default: + errno = EINVAL; + return (NULL); + } +} + +/* + * Return 1, if ACL is trivial, 0 otherwise. + * + * ACL is trivial, iff its meaning could be fully expressed using just file + * mode. In other words, ACL is trivial iff it doesn't have "+" to the right + * of the mode bits in "ls -l" output ;-) + */ +int +acl_is_trivial_np(const acl_t aclp, int *trivialp) +{ + acl_t tmpacl; + int differs; + + if (aclp == NULL || trivialp == NULL) { + errno = EINVAL; + return (-1); + } + + switch (_acl_brand(aclp)) { + case ACL_BRAND_POSIX: + if (aclp->ats_acl.acl_cnt == 3) + *trivialp = 1; + else + *trivialp = 0; + + return (0); + + case ACL_BRAND_NFS4: + /* + * Calculate trivial ACL - using acl_strip_np - and compare + * with the original. + */ + tmpacl = acl_strip_np(aclp, 0); + if (tmpacl == NULL) + return (-1); + + differs = _acl_differs(aclp, tmpacl); + acl_free(tmpacl); + + if (differs) + *trivialp = 0; + else + *trivialp = 1; + + return (0); + + default: + errno = EINVAL; + return (-1); + } +} +/*- + * Copyright (c) 2001 Chris D. Faulhaber + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE VOICES IN HIS HEAD BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <errno.h> +#include <stdio.h> +#include <assert.h> +#include <sys/acl.h> + +#include "acl_support.h" + +/* + * These two routines from sys/kern/subr_acl_nfs4.c are used by both kernel + * and libc. + */ +void acl_nfs4_sync_acl_from_mode(struct acl *aclp, mode_t mode, + int file_owner_id); +void acl_nfs4_sync_mode_from_acl(mode_t *_mode, const struct acl *aclp); + +static acl_t +_nfs4_acl_strip_np(const acl_t aclp, int recalculate_mask) +{ + acl_t newacl; + mode_t mode; + + newacl = acl_init(ACL_MAX_ENTRIES); + if (newacl == NULL) { + errno = ENOMEM; + return (NULL); + } + + _acl_brand_as(newacl, ACL_BRAND_NFS4); + + acl_nfs4_sync_mode_from_acl(&mode, &(aclp->ats_acl)); + acl_nfs4_sync_acl_from_mode(&(newacl->ats_acl), mode, -1); + + return (newacl); +} + +static acl_t +_posix1e_acl_strip_np(const acl_t aclp, int recalculate_mask) +{ + acl_t acl_new, acl_old; + acl_entry_t entry, entry_new; + acl_permset_t perm; + acl_tag_t tag; + int entry_id, have_mask_entry; + + assert(_acl_brand(aclp) == ACL_BRAND_POSIX); + + acl_old = acl_dup(aclp); + if (acl_old == NULL) + return (NULL); + + assert(_acl_brand(acl_old) == ACL_BRAND_POSIX); + + have_mask_entry = 0; + acl_new = acl_init(ACL_MAX_ENTRIES); + if (acl_new == NULL) + return (NULL); + tag = ACL_UNDEFINED_TAG; + + /* only save the default user/group/other entries */ + entry_id = ACL_FIRST_ENTRY; + while (acl_get_entry(acl_old, entry_id, &entry) == 1) { + entry_id = ACL_NEXT_ENTRY; + + assert(_entry_brand(entry) == ACL_BRAND_POSIX); + + if (acl_get_tag_type(entry, &tag) == -1) + return (NULL); + + switch(tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_OTHER: + if (acl_get_tag_type(entry, &tag) == -1) + return (NULL); + if (acl_get_permset(entry, &perm) == -1) + return (NULL); + if (acl_create_entry(&acl_new, &entry_new) == -1) + return (NULL); + if (acl_set_tag_type(entry_new, tag) == -1) + return (NULL); + if (acl_set_permset(entry_new, perm) == -1) + return (NULL); + if (acl_copy_entry(entry_new, entry) == -1) + return (NULL); + assert(_entry_brand(entry_new) == ACL_BRAND_POSIX); + break; + case ACL_MASK: + have_mask_entry = 1; + break; + default: + break; + } + } + + assert(_acl_brand(acl_new) == ACL_BRAND_POSIX); + + if (have_mask_entry && recalculate_mask) { + if (acl_calc_mask(&acl_new) == -1) + return (NULL); + } + + return (acl_new); +} + +acl_t +acl_strip_np(const acl_t aclp, int recalculate_mask) +{ + switch (_acl_brand(aclp)) { + case ACL_BRAND_NFS4: + return (_nfs4_acl_strip_np(aclp, recalculate_mask)); + + case ACL_BRAND_POSIX: + return (_posix1e_acl_strip_np(aclp, recalculate_mask)); + + default: + errno = EINVAL; + return (NULL); + } +} + +/* + * Return 1, if ACL is trivial, 0 otherwise. + * + * ACL is trivial, iff its meaning could be fully expressed using just file + * mode. In other words, ACL is trivial iff it doesn't have "+" to the right + * of the mode bits in "ls -l" output ;-) + */ +int +acl_is_trivial_np(const acl_t aclp, int *trivialp) +{ + acl_t tmpacl; + int differs; + + if (aclp == NULL || trivialp == NULL) { + errno = EINVAL; + return (-1); + } + + switch (_acl_brand(aclp)) { + case ACL_BRAND_POSIX: + if (aclp->ats_acl.acl_cnt == 3) + *trivialp = 1; + else + *trivialp = 0; + + return (0); + + case ACL_BRAND_NFS4: + /* + * Calculate trivial ACL - using acl_strip_np - and compare + * with the original. + */ + tmpacl = acl_strip_np(aclp, 0); + if (tmpacl == NULL) + return (-1); + + differs = _acl_differs(aclp, tmpacl); + acl_free(tmpacl); + + if (differs) + *trivialp = 0; + else + *trivialp = 1; + + return (0); + + default: + errno = EINVAL; + return (-1); + } +} |