acl_common.c revision 1eb4e906ec75b9bde421954ace46ef137b0fc9eb
fa9e4066f08beec538e775443c5be79dd423fcabahrens * CDDL HEADER START
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The contents of this file are subject to the terms of the
f48205be61a214698b763ff550ab9e657525104ccasper * Common Development and Distribution License (the "License").
f48205be61a214698b763ff550ab9e657525104ccasper * You may not use this file except in compliance with the License.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
fa9e4066f08beec538e775443c5be79dd423fcabahrens * See the License for the specific language governing permissions
fa9e4066f08beec538e775443c5be79dd423fcabahrens * and limitations under the License.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * When distributing Covered Code, include this CDDL HEADER in each
fa9e4066f08beec538e775443c5be79dd423fcabahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * If applicable, add the following below this CDDL HEADER, with the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * fields enclosed by brackets "[]" replaced with your own identifying
fa9e4066f08beec538e775443c5be79dd423fcabahrens * information: Portions Copyright [yyyy] [name of copyright owner]
fa9e4066f08beec538e775443c5be79dd423fcabahrens * CDDL HEADER END
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw ACE_SUCCESSFUL_ACCESS_ACE_FLAG | ACE_FAILED_ACCESS_ACE_FLAG | \
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw ACE_IDENTIFIER_GROUP | ACE_OWNER | ACE_GROUP | ACE_EVERYONE)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * ACL conversion helpers
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwtypedef enum {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwtypedef struct acevals {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwtypedef struct ace_list {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw int seen; /* bitmask of all aclent_t a_type values seen */
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Generic shellsort, from K&R (1st ed, p 58.), somewhat modified.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * v = Ptr to array/vector of objs
fa9e4066f08beec538e775443c5be79dd423fcabahrens * n = # objs in the array
fa9e4066f08beec538e775443c5be79dd423fcabahrens * s = size of each obj (must be multiples of a word size)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * f = ptr to function to compare two objs
fa9e4066f08beec538e775443c5be79dd423fcabahrens * returns (-1 = less than, 0 = equal, 1 = greater than
fa9e4066f08beec538e775443c5be79dd423fcabahrens int g, i, j, ii;
fa9e4066f08beec538e775443c5be79dd423fcabahrens unsigned int tmp;
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* No work to do */
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* Sanity check on arguments */
fa9e4066f08beec538e775443c5be79dd423fcabahrens for (i = g; i < n; i++) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens for (j = i - g; j >= 0 &&
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw (*f)(v + j * s, v + (j + g) * s) == 1;
fa9e4066f08beec538e775443c5be79dd423fcabahrens p1 = (void *)(v + j * s);
fa9e4066f08beec538e775443c5be79dd423fcabahrens p2 = (void *)(v + (j + g) * s);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Compare two acls, all fields. Returns:
fa9e4066f08beec538e775443c5be79dd423fcabahrens * -1 (less than)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * 0 (equal)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * +1 (greater than)
fa9e4066f08beec538e775443c5be79dd423fcabahrenscmp2acls(void *a, void *b)
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* Compare types */
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* Equal types; compare id's */
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* Equal ids; compare perms */
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (-1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* Totally equal */
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/*ARGSUSED*/
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void *
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw (void) memcpy(tmp, ptr, (size < new_size) ? size : new_size);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/*ARGSUSED*/
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw switch (type) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Free acl_t structure
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwaccess_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * If the entity is not the owner and does not
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * have write permissions ACE_WRITE_ATTRIBUTES will
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * always go in the DENY ACE.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Given an mode_t, convert it into an access_mask as used
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * by nfsace, assuming aclent_t -> nfsace semantics.
a3c49ce110f325a563c245bedc4d533adddb7211Albert Leemode_to_ace_access(mode_t mode, boolean_t isdir, int isowner, int isallow)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * The following call takes care of correctly setting the following
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * mask bits in the access_mask:
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * ACE_SYNCHRONIZE, ACE_WRITE_OWNER, ACE_DELETE,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * ACE_WRITE_ATTRIBUTES, ACE_WRITE_NAMED_ATTRS, ACE_READ_NAMED_ATTRS
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* read */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* write */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* exec */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Given an nfsace (presumably an ALLOW entry), make a
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * corresponding DENY entry at the address given.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwace_make_deny(ace_t *allow, ace_t *deny, int isdir, int isowner)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw deny->a_access_mask &= ~(ACE_SYNCHRONIZE | ACE_WRITE_OWNER |
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw ACE_DELETE | ACE_WRITE_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw deny->a_access_mask |= access_mask_set((allow->a_access_mask &
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw ACE_WRITE_DATA), (allow->a_access_mask & ACE_READ_DATA), isowner,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Make an initial pass over an array of aclent_t's. Gather
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * information such as an ACL_MASK (if any), number of users,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * number of groups, and whether the array needs to be sorted.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw for (i = 0; i < n; i++) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Convert an array of aclent_t into an array of nfsace entries,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * following POSIX draft -> nfsv4 conversion semantics as outlined in
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * the IETF draft.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwln_aent_to_ace(aclent_t *aclent, int n, ace_t **acepp, int *rescount, int isdir)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* allow + deny for each aclent */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * stick extra deny on the group_obj and on each
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * user|group for the mask (the group_obj was added
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * into the count for numgroup)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* ... and don't count the mask itself */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* sort the source if necessary */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (cacl_malloc((void **)&result, resultsize * sizeof (ace_t)) != 0)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw for (i = 0; i < n; i++) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * don't process CLASS_OBJ (mask); mask was grabbed in
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * ln_aent_preprocess()
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* If we need an ACL_MASK emulator, prepend it now */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Set the access mask for the prepended deny
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * ace. To do this, we invert the mask (found
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * in ln_aent_preprocess()) then convert it to an
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * DENY ace access_mask.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* handle a_perm -> access_mask */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw acep->a_access_mask = mode_to_ace_access(aclent[i].a_perm,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* emulate a default aclent */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * handle a_perm and a_id
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * this must be done last, since it involves the
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * corresponding deny aces, which are handled
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * differently for each different a_type.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Set the corresponding deny for the group ace.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * The deny aces go after all of the groups, unlike
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * everything else, where they immediately follow
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * the allow ace.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * We calculate "skip", the number of slots to
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * skip ahead for the deny ace, here.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * The pattern is:
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * MD1 A1 MD2 A2 MD3 A3 D1 D2 D3
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * thus, skip is
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * (2 * numgroup) - 1 - groupi
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * (2 * numgroup) to account for MD + A
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * - 1 to account for the fact that we're on the
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * access (A), not the mask (MD)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * - groupi to account for the fact that we have
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * passed up groupi number of MD's.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * If we just did the last group, skip acep past
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * all of the denies; else, just move ahead one.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (error != 0) {
a3c49ce110f325a563c245bedc4d533adddb7211Albert Leeconvert_aent_to_ace(aclent_t *aclentp, int aclcnt, boolean_t isdir,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw ksort((caddr_t)aclentp, aclcnt, sizeof (aclent_t), cmp2acls);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = ln_aent_to_ace(aclentp, i, &acep, &acecnt, isdir);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (dfacecnt != 0) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
a3c49ce110f325a563c245bedc4d533adddb7211Albert Leeace_mask_to_mode(uint32_t mask, o_mode_t *modep, boolean_t isdir)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* read */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* write */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (bits != 0) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* exec */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Find or create an acevals holder for a given id and avl tree.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Note that only one thread will ever touch these avl trees, so
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * there is no need for locking.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* this memory is freed by ln_ace_to_aent()->ace_list_free() */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwaccess_mask_check(ace_t *acep, int mask_bit, int isowner)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 0 : 1;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 0 : 1;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 1 : 0;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 1 : 0;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw } else if (haswriteperm) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* ACE_ACCESS_ALLOWED_ACE_TYPE */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* only ALLOW or DENY */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* check for invalid flags */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* some flags are illegal */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* check for invalid masks */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = access_mask_check(acep, ACE_SYNCHRONIZE, isowner);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = access_mask_check(acep, ACE_WRITE_OWNER, isowner);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = access_mask_check(acep, ACE_WRITE_ATTRIBUTES, isowner);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = access_mask_check(acep, ACE_READ_NAMED_ATTRS, isowner);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = access_mask_check(acep, ACE_WRITE_NAMED_ATTRS, isowner);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* more detailed checking of masks */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* ACL enforcement */
a3c49ce110f325a563c245bedc4d533adddb7211Albert Leeace_allow_to_mode(uint32_t mask, o_mode_t *modep, boolean_t isdir)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* ACE_READ_ACL and ACE_READ_ATTRIBUTES must both be set */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwacevals_to_aent(acevals_t *vals, aclent_t *dest, ace_list_t *list,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if ((list->hasmask) && (list->acl_mask != vals->mask) &&
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = ace_allow_to_mode(vals->allowed, &dest->a_perm, isdir);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwace_list_to_aent(ace_list_t *list, aclent_t **aclentp, int *aclcnt,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if ((list->seen & (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) !=
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if ((! list->hasmask) && (list->numusers + list->numgroups > 0)) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * This must be the same condition as below, when we add the CLASS_OBJ
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * (aka ACL mask)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* USER_OBJ */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = acevals_to_aent(&list->user_obj, aent, list, owner, group,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* USER */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* GROUP_OBJ */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = acevals_to_aent(&list->group_obj, aent, list, owner, group,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* GROUP */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * CLASS_OBJ (aka ACL_MASK)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * An ACL_MASK is not fabricated if the ACL is a default ACL.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * This is to follow UFS's behavior.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* fabricate the ACL_MASK from the group permissions */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* OTHER_OBJ */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = acevals_to_aent(&list->other_obj, aent, list, owner, group,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (error != 0) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * free all data associated with an ace_list
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw while ((node = avl_destroy_nodes(&al->user, &cookie)) != NULL)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw while ((node = avl_destroy_nodes(&al->group, &cookie)) != NULL)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* free the container itself */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (1);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (-1);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Convert a list of ace_t entries to equivalent regular and default
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * aclent_t lists. Return error (ENOTSUP) when conversion is not possible.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwln_ace_to_aent(ace_t *ace, int n, uid_t owner, gid_t group,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw aclent_t **aclentp, int *aclcnt, aclent_t **dfaclentp, int *dfaclcnt,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* we need at least user_obj, group_obj, and other_obj */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (n < 6) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = cacl_malloc((void **)&normacl, sizeof (ace_list_t));
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw avl_create(&normacl->user, acevals_compare, sizeof (acevals_t),
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw avl_create(&normacl->group, acevals_compare, sizeof (acevals_t),
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = cacl_malloc((void **)&dfacl, sizeof (ace_list_t));
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw avl_create(&dfacl->user, acevals_compare, sizeof (acevals_t),
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw avl_create(&dfacl->group, acevals_compare, sizeof (acevals_t),
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* process every ace_t... */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw for (i = 0; i < n; i++) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* rule out certain cases quickly */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Turn off these bits in order to not have to worry about
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * them when doing the checks for compliments.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* see if this should be a regular or default acl */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (bits != 0) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* all or nothing on these inherit bits */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* no more than one allowed per aclent_t */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * it's a DENY; if there was a previous DENY, it
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * must have been an ACL_MASK.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* ACL_MASK is for USER and GROUP only */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* check for mismatched ACL_MASK emulations */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* done collating; produce the aclent_t lists */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (error != 0) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (error != 0) {
a3c49ce110f325a563c245bedc4d533adddb7211Albert Leeconvert_ace_to_aent(ace_t *acebufp, int acecnt, boolean_t isdir,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw uid_t owner, gid_t group, aclent_t **retaclentp, int *retaclcnt)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (dfaclcnt != 0) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Slap aclentp and dfaclentp into a single array.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw aclentp = cacl_realloc(aclentp, aclsz, aclsz + dfaclsz);
a3c49ce110f325a563c245bedc4d533adddb7211Albert Leeacl_translate(acl_t *aclp, int target_flavor, boolean_t isdir, uid_t owner,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * See if we need to translate
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if ((target_flavor == _ACL_ACE_ENABLED && aclp->acl_type == ACE_T) ||
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = convert_ace_to_aent(aclp->acl_aclp, aclp->acl_cnt,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * replace old acl with newly translated acl
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw cacl_free(aclp->acl_aclp, aclp->acl_cnt * aclp->acl_entry_size);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (-1);
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum#define SET_ACE(acl, index, who, mask, type, flags) { \
a3c49ce110f325a563c245bedc4d533adddb7211Albert Leeacl_trivial_access_masks(mode_t mode, boolean_t isdir, trivial_acl_t *masks)
a3c49ce110f325a563c245bedc4d533adddb7211Albert Lee uint32_t write_mask = ACE_WRITE_DATA|ACE_APPEND_DATA;
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum if (!(mode & S_IRUSR) && (mode & (S_IRGRP|S_IROTH)))
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum if (!(mode & S_IWUSR) && (mode & (S_IWGRP|S_IWOTH)))
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum if (!(mode & S_IXUSR) && (mode & (S_IXGRP|S_IXOTH)))
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum if ((mode & S_IRUSR) && (!(mode & S_IRGRP) && (mode & S_IROTH)))
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum if ((mode & S_IWUSR) && (!(mode & S_IWGRP) && (mode & S_IWOTH)))
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum if ((mode & S_IXUSR) && (!(mode & S_IXGRP) && (mode & S_IXOTH)))
a3c49ce110f325a563c245bedc4d533adddb7211Albert Lee masks->owner = ACE_WRITE_ATTRIBUTES|ACE_WRITE_OWNER|ACE_WRITE_ACL|
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum ACE_WRITE_NAMED_ATTRS|ACE_READ_ACL|ACE_READ_ATTRIBUTES|
a3c49ce110f325a563c245bedc4d533adddb7211Albert Lee masks->group = ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_NAMED_ATTRS|
a3c49ce110f325a563c245bedc4d533adddb7211Albert Lee masks->everyone = ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_NAMED_ATTRS|
a3c49ce110f325a563c245bedc4d533adddb7211Albert Leeacl_trivial_create(mode_t mode, boolean_t isdir, ace_t **acl, int *count)
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum if ((error = cacl_malloc((void **)acl, *count * sizeof (ace_t))) != 0)
a3c49ce110f325a563c245bedc4d533adddb7211Albert Lee ACE_ACCESS_DENIED_ACE_TYPE, ACE_GROUP|ACE_IDENTIFIER_GROUP);
a3c49ce110f325a563c245bedc4d533adddb7211Albert Lee SET_ACE(acl, index, -1, masks.owner, ACE_ACCESS_ALLOWED_ACE_TYPE,
a3c49ce110f325a563c245bedc4d533adddb7211Albert Lee SET_ACE(acl, index, -1, masks.group, ACE_ACCESS_ALLOWED_ACE_TYPE,
a3c49ce110f325a563c245bedc4d533adddb7211Albert Lee SET_ACE(acl, index, -1, masks.everyone, ACE_ACCESS_ALLOWED_ACE_TYPE,
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum * ace_trivial:
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum * determine whether an ace_t acl is trivial
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum * Trivialness implies that the acl is composed of only
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum * owner, group, everyone entries. ACL can't
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum * have read_acl denied, and write_owner/write_acl/write_attributes
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum * can only be owner@ entry.
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum uint64_t (*walk)(void *, uint64_t, int aclcnt,
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum while (cookie = walk(acep, cookie, aclcnt, &flags, &type, &mask)) {
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum ACE_DIRECTORY_INHERIT_ACE|ACE_NO_PROPAGATE_INHERIT_ACE|
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum * Special check for some special bits
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum * Don't allow anybody to deny reading basic
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum * attributes or a files ACL.
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum if ((mask & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) &&
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * Delete permission is never set by default
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * Child delete permission should be accompanied by write
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe if ((mask & ACE_DELETE_CHILD) && !(mask & ACE_WRITE_DATA))
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum * only allow owner@ to have
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum * write_acl/write_owner/write_attributes/write_xattr/
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum (ACE_WRITE_OWNER|ACE_WRITE_ACL| ACE_WRITE_ATTRIBUTES|
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaumace_walk(void *datap, uint64_t cookie, int aclcnt, uint16_t *flags,