1789Sahrens /*
2789Sahrens * CDDL HEADER START
3789Sahrens *
4789Sahrens * The contents of this file are subject to the terms of the
54321Scasper * Common Development and Distribution License (the "License").
64321Scasper * You may not use this file except in compliance with the License.
7789Sahrens *
8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9789Sahrens * or http://www.opensolaris.org/os/licensing.
10789Sahrens * See the License for the specific language governing permissions
11789Sahrens * and limitations under the License.
12789Sahrens *
13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each
14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15789Sahrens * If applicable, add the following below this CDDL HEADER, with the
16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying
17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner]
18789Sahrens *
19789Sahrens * CDDL HEADER END
20789Sahrens */
21789Sahrens /*
22*12164SMark.Shellenbaum@Sun.COM * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23789Sahrens */
24789Sahrens
25789Sahrens #include <sys/types.h>
26789Sahrens #include <sys/stat.h>
275331Samw #include <sys/avl.h>
28789Sahrens #if defined(_KERNEL)
29789Sahrens #include <sys/systm.h>
305331Samw #include <sys/sysmacros.h>
315331Samw #include <acl/acl_common.h>
32789Sahrens #else
33789Sahrens #include <errno.h>
34789Sahrens #include <stdlib.h>
355331Samw #include <stddef.h>
36789Sahrens #include <strings.h>
375331Samw #include <unistd.h>
38789Sahrens #include <assert.h>
395331Samw #include <grp.h>
405331Samw #include <pwd.h>
415331Samw #include <acl_common.h>
42789Sahrens #define ASSERT assert
43789Sahrens #endif
44789Sahrens
455331Samw #define ACE_POSIX_SUPPORTED_BITS (ACE_READ_DATA | \
465331Samw ACE_WRITE_DATA | ACE_APPEND_DATA | ACE_EXECUTE | \
475331Samw ACE_READ_ATTRIBUTES | ACE_READ_ACL | ACE_WRITE_ACL)
485331Samw
495331Samw
505331Samw #define ACL_SYNCHRONIZE_SET_DENY 0x0000001
515331Samw #define ACL_SYNCHRONIZE_SET_ALLOW 0x0000002
525331Samw #define ACL_SYNCHRONIZE_ERR_DENY 0x0000004
535331Samw #define ACL_SYNCHRONIZE_ERR_ALLOW 0x0000008
545331Samw
555331Samw #define ACL_WRITE_OWNER_SET_DENY 0x0000010
565331Samw #define ACL_WRITE_OWNER_SET_ALLOW 0x0000020
575331Samw #define ACL_WRITE_OWNER_ERR_DENY 0x0000040
585331Samw #define ACL_WRITE_OWNER_ERR_ALLOW 0x0000080
595331Samw
605331Samw #define ACL_DELETE_SET_DENY 0x0000100
615331Samw #define ACL_DELETE_SET_ALLOW 0x0000200
625331Samw #define ACL_DELETE_ERR_DENY 0x0000400
635331Samw #define ACL_DELETE_ERR_ALLOW 0x0000800
645331Samw
655331Samw #define ACL_WRITE_ATTRS_OWNER_SET_DENY 0x0001000
665331Samw #define ACL_WRITE_ATTRS_OWNER_SET_ALLOW 0x0002000
675331Samw #define ACL_WRITE_ATTRS_OWNER_ERR_DENY 0x0004000
685331Samw #define ACL_WRITE_ATTRS_OWNER_ERR_ALLOW 0x0008000
695331Samw
705331Samw #define ACL_WRITE_ATTRS_WRITER_SET_DENY 0x0010000
715331Samw #define ACL_WRITE_ATTRS_WRITER_SET_ALLOW 0x0020000
725331Samw #define ACL_WRITE_ATTRS_WRITER_ERR_DENY 0x0040000
735331Samw #define ACL_WRITE_ATTRS_WRITER_ERR_ALLOW 0x0080000
745331Samw
755331Samw #define ACL_WRITE_NAMED_WRITER_SET_DENY 0x0100000
765331Samw #define ACL_WRITE_NAMED_WRITER_SET_ALLOW 0x0200000
775331Samw #define ACL_WRITE_NAMED_WRITER_ERR_DENY 0x0400000
785331Samw #define ACL_WRITE_NAMED_WRITER_ERR_ALLOW 0x0800000
795331Samw
805331Samw #define ACL_READ_NAMED_READER_SET_DENY 0x1000000
815331Samw #define ACL_READ_NAMED_READER_SET_ALLOW 0x2000000
825331Samw #define ACL_READ_NAMED_READER_ERR_DENY 0x4000000
835331Samw #define ACL_READ_NAMED_READER_ERR_ALLOW 0x8000000
845331Samw
855331Samw
865331Samw #define ACE_VALID_MASK_BITS (\
875331Samw ACE_READ_DATA | \
885331Samw ACE_LIST_DIRECTORY | \
895331Samw ACE_WRITE_DATA | \
905331Samw ACE_ADD_FILE | \
915331Samw ACE_APPEND_DATA | \
925331Samw ACE_ADD_SUBDIRECTORY | \
935331Samw ACE_READ_NAMED_ATTRS | \
945331Samw ACE_WRITE_NAMED_ATTRS | \
955331Samw ACE_EXECUTE | \
965331Samw ACE_DELETE_CHILD | \
975331Samw ACE_READ_ATTRIBUTES | \
985331Samw ACE_WRITE_ATTRIBUTES | \
995331Samw ACE_DELETE | \
1005331Samw ACE_READ_ACL | \
1015331Samw ACE_WRITE_ACL | \
1025331Samw ACE_WRITE_OWNER | \
1035331Samw ACE_SYNCHRONIZE)
1045331Samw
1055331Samw #define ACE_MASK_UNDEFINED 0x80000000
1065331Samw
1075331Samw #define ACE_VALID_FLAG_BITS (ACE_FILE_INHERIT_ACE | \
1085331Samw ACE_DIRECTORY_INHERIT_ACE | \
1095331Samw ACE_NO_PROPAGATE_INHERIT_ACE | ACE_INHERIT_ONLY_ACE | \
1105331Samw ACE_SUCCESSFUL_ACCESS_ACE_FLAG | ACE_FAILED_ACCESS_ACE_FLAG | \
1115331Samw ACE_IDENTIFIER_GROUP | ACE_OWNER | ACE_GROUP | ACE_EVERYONE)
1125331Samw
1135331Samw /*
1145331Samw * ACL conversion helpers
1155331Samw */
1165331Samw
1175331Samw typedef enum {
1185331Samw ace_unused,
1195331Samw ace_user_obj,
1205331Samw ace_user,
1215331Samw ace_group, /* includes GROUP and GROUP_OBJ */
1225331Samw ace_other_obj
1235331Samw } ace_to_aent_state_t;
1245331Samw
1255331Samw typedef struct acevals {
1265331Samw uid_t key;
1275331Samw avl_node_t avl;
1285331Samw uint32_t mask;
1295331Samw uint32_t allowed;
1305331Samw uint32_t denied;
1315331Samw int aent_type;
1325331Samw } acevals_t;
1335331Samw
1345331Samw typedef struct ace_list {
1355331Samw acevals_t user_obj;
1365331Samw avl_tree_t user;
1375331Samw int numusers;
1385331Samw acevals_t group_obj;
1395331Samw avl_tree_t group;
1405331Samw int numgroups;
1415331Samw acevals_t other_obj;
1425331Samw uint32_t acl_mask;
1435331Samw int hasmask;
1445331Samw int dfacl_flag;
1455331Samw ace_to_aent_state_t state;
1465331Samw int seen; /* bitmask of all aclent_t a_type values seen */
1475331Samw } ace_list_t;
148789Sahrens
149789Sahrens /*
150789Sahrens * Generic shellsort, from K&R (1st ed, p 58.), somewhat modified.
151789Sahrens * v = Ptr to array/vector of objs
152789Sahrens * n = # objs in the array
153789Sahrens * s = size of each obj (must be multiples of a word size)
154789Sahrens * f = ptr to function to compare two objs
155789Sahrens * returns (-1 = less than, 0 = equal, 1 = greater than
156789Sahrens */
157789Sahrens void
ksort(caddr_t v,int n,int s,int (* f)())158789Sahrens ksort(caddr_t v, int n, int s, int (*f)())
159789Sahrens {
160789Sahrens int g, i, j, ii;
161789Sahrens unsigned int *p1, *p2;
162789Sahrens unsigned int tmp;
163789Sahrens
164789Sahrens /* No work to do */
165789Sahrens if (v == NULL || n <= 1)
166789Sahrens return;
167789Sahrens
168789Sahrens /* Sanity check on arguments */
169789Sahrens ASSERT(((uintptr_t)v & 0x3) == 0 && (s & 0x3) == 0);
170789Sahrens ASSERT(s > 0);
171789Sahrens for (g = n / 2; g > 0; g /= 2) {
172789Sahrens for (i = g; i < n; i++) {
173789Sahrens for (j = i - g; j >= 0 &&
1745331Samw (*f)(v + j * s, v + (j + g) * s) == 1;
1755331Samw j -= g) {
176789Sahrens p1 = (void *)(v + j * s);
177789Sahrens p2 = (void *)(v + (j + g) * s);
178789Sahrens for (ii = 0; ii < s / 4; ii++) {
179789Sahrens tmp = *p1;
180789Sahrens *p1++ = *p2;
181789Sahrens *p2++ = tmp;
182789Sahrens }
183789Sahrens }
184789Sahrens }
185789Sahrens }
186789Sahrens }
187789Sahrens
188789Sahrens /*
189789Sahrens * Compare two acls, all fields. Returns:
190789Sahrens * -1 (less than)
191789Sahrens * 0 (equal)
192789Sahrens * +1 (greater than)
193789Sahrens */
194789Sahrens int
cmp2acls(void * a,void * b)195789Sahrens cmp2acls(void *a, void *b)
196789Sahrens {
197789Sahrens aclent_t *x = (aclent_t *)a;
198789Sahrens aclent_t *y = (aclent_t *)b;
199789Sahrens
200789Sahrens /* Compare types */
201789Sahrens if (x->a_type < y->a_type)
202789Sahrens return (-1);
203789Sahrens if (x->a_type > y->a_type)
204789Sahrens return (1);
205789Sahrens /* Equal types; compare id's */
206789Sahrens if (x->a_id < y->a_id)
207789Sahrens return (-1);
208789Sahrens if (x->a_id > y->a_id)
209789Sahrens return (1);
210789Sahrens /* Equal ids; compare perms */
211789Sahrens if (x->a_perm < y->a_perm)
212789Sahrens return (-1);
213789Sahrens if (x->a_perm > y->a_perm)
214789Sahrens return (1);
215789Sahrens /* Totally equal */
216789Sahrens return (0);
217789Sahrens }
2185331Samw
2195331Samw /*ARGSUSED*/
2205331Samw static void *
cacl_realloc(void * ptr,size_t size,size_t new_size)2215331Samw cacl_realloc(void *ptr, size_t size, size_t new_size)
2225331Samw {
2235331Samw #if defined(_KERNEL)
2245331Samw void *tmp;
2255331Samw
2265331Samw tmp = kmem_alloc(new_size, KM_SLEEP);
2275331Samw (void) memcpy(tmp, ptr, (size < new_size) ? size : new_size);
2285331Samw kmem_free(ptr, size);
2295331Samw return (tmp);
2305331Samw #else
2315331Samw return (realloc(ptr, new_size));
2325331Samw #endif
2335331Samw }
2345331Samw
2355331Samw static int
cacl_malloc(void ** ptr,size_t size)2365331Samw cacl_malloc(void **ptr, size_t size)
2375331Samw {
2385331Samw #if defined(_KERNEL)
2395331Samw *ptr = kmem_zalloc(size, KM_SLEEP);
2405331Samw return (0);
2415331Samw #else
2425331Samw *ptr = calloc(1, size);
2435331Samw if (*ptr == NULL)
2445331Samw return (errno);
2455331Samw
2465331Samw return (0);
2475331Samw #endif
2485331Samw }
2495331Samw
2505331Samw /*ARGSUSED*/
2515331Samw static void
cacl_free(void * ptr,size_t size)2525331Samw cacl_free(void *ptr, size_t size)
2535331Samw {
2545331Samw #if defined(_KERNEL)
2555331Samw kmem_free(ptr, size);
2565331Samw #else
2575331Samw free(ptr);
2585331Samw #endif
2595331Samw }
2605331Samw
2615331Samw acl_t *
acl_alloc(enum acl_type type)2625331Samw acl_alloc(enum acl_type type)
2635331Samw {
2645331Samw acl_t *aclp;
2655331Samw
2665331Samw if (cacl_malloc((void **)&aclp, sizeof (acl_t)) != 0)
2675331Samw return (NULL);
2685331Samw
2695331Samw aclp->acl_aclp = NULL;
2705331Samw aclp->acl_cnt = 0;
2715331Samw
2725331Samw switch (type) {
2735331Samw case ACE_T:
2745331Samw aclp->acl_type = ACE_T;
2755331Samw aclp->acl_entry_size = sizeof (ace_t);
2765331Samw break;
2775331Samw case ACLENT_T:
2785331Samw aclp->acl_type = ACLENT_T;
2795331Samw aclp->acl_entry_size = sizeof (aclent_t);
2805331Samw break;
2815331Samw default:
2825331Samw acl_free(aclp);
2835331Samw aclp = NULL;
2845331Samw }
2855331Samw return (aclp);
2865331Samw }
2875331Samw
2885331Samw /*
2895331Samw * Free acl_t structure
2905331Samw */
2915331Samw void
acl_free(acl_t * aclp)2925331Samw acl_free(acl_t *aclp)
2935331Samw {
2945331Samw int acl_size;
2955331Samw
2965331Samw if (aclp == NULL)
2975331Samw return;
2985331Samw
2995331Samw if (aclp->acl_aclp) {
3005331Samw acl_size = aclp->acl_cnt * aclp->acl_entry_size;
3015331Samw cacl_free(aclp->acl_aclp, acl_size);
3025331Samw }
3035331Samw
3045331Samw cacl_free(aclp, sizeof (acl_t));
3055331Samw }
3065331Samw
3075331Samw static uint32_t
access_mask_set(int haswriteperm,int hasreadperm,int isowner,int isallow)3085331Samw access_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow)
3095331Samw {
3105331Samw uint32_t access_mask = 0;
3115331Samw int acl_produce;
3125331Samw int synchronize_set = 0, write_owner_set = 0;
3135331Samw int delete_set = 0, write_attrs_set = 0;
3145331Samw int read_named_set = 0, write_named_set = 0;
3155331Samw
3165331Samw acl_produce = (ACL_SYNCHRONIZE_SET_ALLOW |
3175331Samw ACL_WRITE_ATTRS_OWNER_SET_ALLOW |
3185331Samw ACL_WRITE_ATTRS_WRITER_SET_DENY);
3195331Samw
3205331Samw if (isallow) {
3215331Samw synchronize_set = ACL_SYNCHRONIZE_SET_ALLOW;
3225331Samw write_owner_set = ACL_WRITE_OWNER_SET_ALLOW;
3235331Samw delete_set = ACL_DELETE_SET_ALLOW;
3245331Samw if (hasreadperm)
3255331Samw read_named_set = ACL_READ_NAMED_READER_SET_ALLOW;
3265331Samw if (haswriteperm)
3275331Samw write_named_set = ACL_WRITE_NAMED_WRITER_SET_ALLOW;
3285331Samw if (isowner)
3295331Samw write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_ALLOW;
3305331Samw else if (haswriteperm)
3315331Samw write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_ALLOW;
3325331Samw } else {
3335331Samw
3345331Samw synchronize_set = ACL_SYNCHRONIZE_SET_DENY;
3355331Samw write_owner_set = ACL_WRITE_OWNER_SET_DENY;
3365331Samw delete_set = ACL_DELETE_SET_DENY;
3375331Samw if (hasreadperm)
3385331Samw read_named_set = ACL_READ_NAMED_READER_SET_DENY;
3395331Samw if (haswriteperm)
3405331Samw write_named_set = ACL_WRITE_NAMED_WRITER_SET_DENY;
3415331Samw if (isowner)
3425331Samw write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_DENY;
3435331Samw else if (haswriteperm)
3445331Samw write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_DENY;
3455331Samw else
3465331Samw /*
3475331Samw * If the entity is not the owner and does not
3485331Samw * have write permissions ACE_WRITE_ATTRIBUTES will
3495331Samw * always go in the DENY ACE.
3505331Samw */
3515331Samw access_mask |= ACE_WRITE_ATTRIBUTES;
3525331Samw }
3535331Samw
3545331Samw if (acl_produce & synchronize_set)
3555331Samw access_mask |= ACE_SYNCHRONIZE;
3565331Samw if (acl_produce & write_owner_set)
3575331Samw access_mask |= ACE_WRITE_OWNER;
3585331Samw if (acl_produce & delete_set)
3595331Samw access_mask |= ACE_DELETE;
3605331Samw if (acl_produce & write_attrs_set)
3615331Samw access_mask |= ACE_WRITE_ATTRIBUTES;
3625331Samw if (acl_produce & read_named_set)
3635331Samw access_mask |= ACE_READ_NAMED_ATTRS;
3645331Samw if (acl_produce & write_named_set)
3655331Samw access_mask |= ACE_WRITE_NAMED_ATTRS;
3665331Samw
3675331Samw return (access_mask);
3685331Samw }
3695331Samw
3705331Samw /*
3715331Samw * Given an mode_t, convert it into an access_mask as used
3725331Samw * by nfsace, assuming aclent_t -> nfsace semantics.
3735331Samw */
3745331Samw static uint32_t
mode_to_ace_access(mode_t mode,int isdir,int isowner,int isallow)3755331Samw mode_to_ace_access(mode_t mode, int isdir, int isowner, int isallow)
3765331Samw {
3775331Samw uint32_t access = 0;
3785331Samw int haswriteperm = 0;
3795331Samw int hasreadperm = 0;
3805331Samw
3815331Samw if (isallow) {
3825331Samw haswriteperm = (mode & S_IWOTH);
3835331Samw hasreadperm = (mode & S_IROTH);
3845331Samw } else {
3855331Samw haswriteperm = !(mode & S_IWOTH);
3865331Samw hasreadperm = !(mode & S_IROTH);
3875331Samw }
3885331Samw
3895331Samw /*
3905331Samw * The following call takes care of correctly setting the following
3915331Samw * mask bits in the access_mask:
3925331Samw * ACE_SYNCHRONIZE, ACE_WRITE_OWNER, ACE_DELETE,
3935331Samw * ACE_WRITE_ATTRIBUTES, ACE_WRITE_NAMED_ATTRS, ACE_READ_NAMED_ATTRS
3945331Samw */
3955331Samw access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow);
3965331Samw
3975331Samw if (isallow) {
3985331Samw access |= ACE_READ_ACL | ACE_READ_ATTRIBUTES;
3995331Samw if (isowner)
4005331Samw access |= ACE_WRITE_ACL;
4015331Samw } else {
4025331Samw if (! isowner)
4035331Samw access |= ACE_WRITE_ACL;
4045331Samw }
4055331Samw
4065331Samw /* read */
4075331Samw if (mode & S_IROTH) {
4085331Samw access |= ACE_READ_DATA;
4095331Samw }
4105331Samw /* write */
4115331Samw if (mode & S_IWOTH) {
4125331Samw access |= ACE_WRITE_DATA |
4135331Samw ACE_APPEND_DATA;
4145331Samw if (isdir)
4155331Samw access |= ACE_DELETE_CHILD;
4165331Samw }
4175331Samw /* exec */
4185331Samw if (mode & 01) {
4195331Samw access |= ACE_EXECUTE;
4205331Samw }
4215331Samw
4225331Samw return (access);
4235331Samw }
4245331Samw
4255331Samw /*
4265331Samw * Given an nfsace (presumably an ALLOW entry), make a
4275331Samw * corresponding DENY entry at the address given.
4285331Samw */
4295331Samw static void
ace_make_deny(ace_t * allow,ace_t * deny,int isdir,int isowner)4305331Samw ace_make_deny(ace_t *allow, ace_t *deny, int isdir, int isowner)
4315331Samw {
4325331Samw (void) memcpy(deny, allow, sizeof (ace_t));
4335331Samw
4345331Samw deny->a_who = allow->a_who;
4355331Samw
4365331Samw deny->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
4375331Samw deny->a_access_mask ^= ACE_POSIX_SUPPORTED_BITS;
4385331Samw if (isdir)
4395331Samw deny->a_access_mask ^= ACE_DELETE_CHILD;
4405331Samw
4415331Samw deny->a_access_mask &= ~(ACE_SYNCHRONIZE | ACE_WRITE_OWNER |
4425331Samw ACE_DELETE | ACE_WRITE_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
4435331Samw ACE_WRITE_NAMED_ATTRS);
4445331Samw deny->a_access_mask |= access_mask_set((allow->a_access_mask &
4455331Samw ACE_WRITE_DATA), (allow->a_access_mask & ACE_READ_DATA), isowner,
4465331Samw B_FALSE);
4475331Samw }
4485331Samw /*
4495331Samw * Make an initial pass over an array of aclent_t's. Gather
4505331Samw * information such as an ACL_MASK (if any), number of users,
4515331Samw * number of groups, and whether the array needs to be sorted.
4525331Samw */
4535331Samw static int
ln_aent_preprocess(aclent_t * aclent,int n,int * hasmask,mode_t * mask,int * numuser,int * numgroup,int * needsort)4545331Samw ln_aent_preprocess(aclent_t *aclent, int n,
4555331Samw int *hasmask, mode_t *mask,
4565331Samw int *numuser, int *numgroup, int *needsort)
4575331Samw {
4585331Samw int error = 0;
4595331Samw int i;
4605331Samw int curtype = 0;
4615331Samw
4625331Samw *hasmask = 0;
4635331Samw *mask = 07;
4645331Samw *needsort = 0;
4655331Samw *numuser = 0;
4665331Samw *numgroup = 0;
4675331Samw
4685331Samw for (i = 0; i < n; i++) {
4695331Samw if (aclent[i].a_type < curtype)
4705331Samw *needsort = 1;
4715331Samw else if (aclent[i].a_type > curtype)
4725331Samw curtype = aclent[i].a_type;
4735331Samw if (aclent[i].a_type & USER)
4745331Samw (*numuser)++;
4755331Samw if (aclent[i].a_type & (GROUP | GROUP_OBJ))
4765331Samw (*numgroup)++;
4775331Samw if (aclent[i].a_type & CLASS_OBJ) {
4785331Samw if (*hasmask) {
4795331Samw error = EINVAL;
4805331Samw goto out;
4815331Samw } else {
4825331Samw *hasmask = 1;
4835331Samw *mask = aclent[i].a_perm;
4845331Samw }
4855331Samw }
4865331Samw }
4875331Samw
4885331Samw if ((! *hasmask) && (*numuser + *numgroup > 1)) {
4895331Samw error = EINVAL;
4905331Samw goto out;
4915331Samw }
4925331Samw
4935331Samw out:
4945331Samw return (error);
4955331Samw }
4965331Samw
4975331Samw /*
4985331Samw * Convert an array of aclent_t into an array of nfsace entries,
4995331Samw * following POSIX draft -> nfsv4 conversion semantics as outlined in
5005331Samw * the IETF draft.
5015331Samw */
5025331Samw static int
ln_aent_to_ace(aclent_t * aclent,int n,ace_t ** acepp,int * rescount,int isdir)5035331Samw ln_aent_to_ace(aclent_t *aclent, int n, ace_t **acepp, int *rescount, int isdir)
5045331Samw {
5055331Samw int error = 0;
5065331Samw mode_t mask;
5075331Samw int numuser, numgroup, needsort;
5085331Samw int resultsize = 0;
5095331Samw int i, groupi = 0, skip;
5105331Samw ace_t *acep, *result = NULL;
5115331Samw int hasmask;
5125331Samw
5135331Samw error = ln_aent_preprocess(aclent, n, &hasmask, &mask,
5145331Samw &numuser, &numgroup, &needsort);
5155331Samw if (error != 0)
5165331Samw goto out;
5175331Samw
5185331Samw /* allow + deny for each aclent */
5195331Samw resultsize = n * 2;
5205331Samw if (hasmask) {
5215331Samw /*
5225331Samw * stick extra deny on the group_obj and on each
5235331Samw * user|group for the mask (the group_obj was added
5245331Samw * into the count for numgroup)
5255331Samw */
5265331Samw resultsize += numuser + numgroup;
5275331Samw /* ... and don't count the mask itself */
5285331Samw resultsize -= 2;
5295331Samw }
5305331Samw
5315331Samw /* sort the source if necessary */
5325331Samw if (needsort)
5335331Samw ksort((caddr_t)aclent, n, sizeof (aclent_t), cmp2acls);
5345331Samw
5355331Samw if (cacl_malloc((void **)&result, resultsize * sizeof (ace_t)) != 0)
5365331Samw goto out;
5375331Samw
5385331Samw acep = result;
5395331Samw
5405331Samw for (i = 0; i < n; i++) {
5415331Samw /*
5425331Samw * don't process CLASS_OBJ (mask); mask was grabbed in
5435331Samw * ln_aent_preprocess()
5445331Samw */
5455331Samw if (aclent[i].a_type & CLASS_OBJ)
5465331Samw continue;
5475331Samw
5485331Samw /* If we need an ACL_MASK emulator, prepend it now */
5495331Samw if ((hasmask) &&
5505331Samw (aclent[i].a_type & (USER | GROUP | GROUP_OBJ))) {
5515331Samw acep->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
5525331Samw acep->a_flags = 0;
5535331Samw if (aclent[i].a_type & GROUP_OBJ) {
5545331Samw acep->a_who = (uid_t)-1;
5555331Samw acep->a_flags |=
5565331Samw (ACE_IDENTIFIER_GROUP|ACE_GROUP);
5575331Samw } else if (aclent[i].a_type & USER) {
5585331Samw acep->a_who = aclent[i].a_id;
5595331Samw } else {
5605331Samw acep->a_who = aclent[i].a_id;
5615331Samw acep->a_flags |= ACE_IDENTIFIER_GROUP;
5625331Samw }
5635331Samw if (aclent[i].a_type & ACL_DEFAULT) {
5645331Samw acep->a_flags |= ACE_INHERIT_ONLY_ACE |
5655331Samw ACE_FILE_INHERIT_ACE |
5665331Samw ACE_DIRECTORY_INHERIT_ACE;
5675331Samw }
5685331Samw /*
5695331Samw * Set the access mask for the prepended deny
5705331Samw * ace. To do this, we invert the mask (found
5715331Samw * in ln_aent_preprocess()) then convert it to an
5725331Samw * DENY ace access_mask.
5735331Samw */
5745331Samw acep->a_access_mask = mode_to_ace_access((mask ^ 07),
5755331Samw isdir, 0, 0);
5765331Samw acep += 1;
5775331Samw }
5785331Samw
5795331Samw /* handle a_perm -> access_mask */
5805331Samw acep->a_access_mask = mode_to_ace_access(aclent[i].a_perm,
5815331Samw isdir, aclent[i].a_type & USER_OBJ, 1);
5825331Samw
5835331Samw /* emulate a default aclent */
5845331Samw if (aclent[i].a_type & ACL_DEFAULT) {
5855331Samw acep->a_flags |= ACE_INHERIT_ONLY_ACE |
5865331Samw ACE_FILE_INHERIT_ACE |
5875331Samw ACE_DIRECTORY_INHERIT_ACE;
5885331Samw }
5895331Samw
5905331Samw /*
5915331Samw * handle a_perm and a_id
5925331Samw *
5935331Samw * this must be done last, since it involves the
5945331Samw * corresponding deny aces, which are handled
5955331Samw * differently for each different a_type.
5965331Samw */
5975331Samw if (aclent[i].a_type & USER_OBJ) {
5985331Samw acep->a_who = (uid_t)-1;
5995331Samw acep->a_flags |= ACE_OWNER;
6005331Samw ace_make_deny(acep, acep + 1, isdir, B_TRUE);
6015331Samw acep += 2;
6025331Samw } else if (aclent[i].a_type & USER) {
6035331Samw acep->a_who = aclent[i].a_id;
6045331Samw ace_make_deny(acep, acep + 1, isdir, B_FALSE);
6055331Samw acep += 2;
6065331Samw } else if (aclent[i].a_type & (GROUP_OBJ | GROUP)) {
6075331Samw if (aclent[i].a_type & GROUP_OBJ) {
6085331Samw acep->a_who = (uid_t)-1;
6095331Samw acep->a_flags |= ACE_GROUP;
6105331Samw } else {
6115331Samw acep->a_who = aclent[i].a_id;
6125331Samw }
6135331Samw acep->a_flags |= ACE_IDENTIFIER_GROUP;
6145331Samw /*
6155331Samw * Set the corresponding deny for the group ace.
6165331Samw *
6175331Samw * The deny aces go after all of the groups, unlike
6185331Samw * everything else, where they immediately follow
6195331Samw * the allow ace.
6205331Samw *
6215331Samw * We calculate "skip", the number of slots to
6225331Samw * skip ahead for the deny ace, here.
6235331Samw *
6245331Samw * The pattern is:
6255331Samw * MD1 A1 MD2 A2 MD3 A3 D1 D2 D3
6265331Samw * thus, skip is
6275331Samw * (2 * numgroup) - 1 - groupi
6285331Samw * (2 * numgroup) to account for MD + A
6295331Samw * - 1 to account for the fact that we're on the
6305331Samw * access (A), not the mask (MD)
6315331Samw * - groupi to account for the fact that we have
6325331Samw * passed up groupi number of MD's.
6335331Samw */
6345331Samw skip = (2 * numgroup) - 1 - groupi;
6355331Samw ace_make_deny(acep, acep + skip, isdir, B_FALSE);
6365331Samw /*
6375331Samw * If we just did the last group, skip acep past
6385331Samw * all of the denies; else, just move ahead one.
6395331Samw */
6405331Samw if (++groupi >= numgroup)
6415331Samw acep += numgroup + 1;
6425331Samw else
6435331Samw acep += 1;
6445331Samw } else if (aclent[i].a_type & OTHER_OBJ) {
6455331Samw acep->a_who = (uid_t)-1;
6465331Samw acep->a_flags |= ACE_EVERYONE;
6475331Samw ace_make_deny(acep, acep + 1, isdir, B_FALSE);
6485331Samw acep += 2;
6495331Samw } else {
6505331Samw error = EINVAL;
6515331Samw goto out;
6525331Samw }
6535331Samw }
6545331Samw
6555331Samw *acepp = result;
6565331Samw *rescount = resultsize;
6575331Samw
6585331Samw out:
6595331Samw if (error != 0) {
6605331Samw if ((result != NULL) && (resultsize > 0)) {
6615331Samw cacl_free(result, resultsize * sizeof (ace_t));
6625331Samw }
6635331Samw }
6645331Samw
6655331Samw return (error);
6665331Samw }
6675331Samw
6685331Samw static int
convert_aent_to_ace(aclent_t * aclentp,int aclcnt,int isdir,ace_t ** retacep,int * retacecnt)6695331Samw convert_aent_to_ace(aclent_t *aclentp, int aclcnt, int isdir,
6705331Samw ace_t **retacep, int *retacecnt)
6715331Samw {
6725331Samw ace_t *acep;
6735331Samw ace_t *dfacep;
6745331Samw int acecnt = 0;
6755331Samw int dfacecnt = 0;
6765331Samw int dfaclstart = 0;
6775331Samw int dfaclcnt = 0;
6785331Samw aclent_t *aclp;
6795331Samw int i;
6805331Samw int error;
6815331Samw int acesz, dfacesz;
6825331Samw
6835331Samw ksort((caddr_t)aclentp, aclcnt, sizeof (aclent_t), cmp2acls);
6845331Samw
6855331Samw for (i = 0, aclp = aclentp; i < aclcnt; aclp++, i++) {
6865331Samw if (aclp->a_type & ACL_DEFAULT)
6875331Samw break;
6885331Samw }
6895331Samw
6905331Samw if (i < aclcnt) {
6915331Samw dfaclstart = i;
6925331Samw dfaclcnt = aclcnt - i;
6935331Samw }
6945331Samw
6955331Samw if (dfaclcnt && isdir == 0) {
6965331Samw return (EINVAL);
6975331Samw }
6985331Samw
6995331Samw error = ln_aent_to_ace(aclentp, i, &acep, &acecnt, isdir);
7005331Samw if (error)
7015331Samw return (error);
7025331Samw
7035331Samw if (dfaclcnt) {
7045331Samw error = ln_aent_to_ace(&aclentp[dfaclstart], dfaclcnt,
7055331Samw &dfacep, &dfacecnt, isdir);
7065331Samw if (error) {
7075331Samw if (acep) {
7085331Samw cacl_free(acep, acecnt * sizeof (ace_t));
7095331Samw }
7105331Samw return (error);
7115331Samw }
7125331Samw }
7135331Samw
7145331Samw if (dfacecnt != 0) {
7155331Samw acesz = sizeof (ace_t) * acecnt;
7165331Samw dfacesz = sizeof (ace_t) * dfacecnt;
7175331Samw acep = cacl_realloc(acep, acesz, acesz + dfacesz);
7185331Samw if (acep == NULL)
7195331Samw return (ENOMEM);
7205331Samw if (dfaclcnt) {
7215331Samw (void) memcpy(acep + acecnt, dfacep, dfacesz);
7225331Samw }
7235331Samw }
7245331Samw if (dfaclcnt)
7255331Samw cacl_free(dfacep, dfacecnt * sizeof (ace_t));
7265331Samw
7275331Samw *retacecnt = acecnt + dfacecnt;
7285331Samw *retacep = acep;
7295331Samw return (0);
7305331Samw }
7315331Samw
7325331Samw static int
ace_mask_to_mode(uint32_t mask,o_mode_t * modep,int isdir)7335331Samw ace_mask_to_mode(uint32_t mask, o_mode_t *modep, int isdir)
7345331Samw {
7355331Samw int error = 0;
7365331Samw o_mode_t mode = 0;
7375331Samw uint32_t bits, wantbits;
7385331Samw
7395331Samw /* read */
7405331Samw if (mask & ACE_READ_DATA)
7415331Samw mode |= S_IROTH;
7425331Samw
7435331Samw /* write */
7445331Samw wantbits = (ACE_WRITE_DATA | ACE_APPEND_DATA);
7455331Samw if (isdir)
7465331Samw wantbits |= ACE_DELETE_CHILD;
7475331Samw bits = mask & wantbits;
7485331Samw if (bits != 0) {
7495331Samw if (bits != wantbits) {
7505331Samw error = ENOTSUP;
7515331Samw goto out;
7525331Samw }
7535331Samw mode |= S_IWOTH;
7545331Samw }
7555331Samw
7565331Samw /* exec */
7575331Samw if (mask & ACE_EXECUTE) {
7585331Samw mode |= S_IXOTH;
7595331Samw }
7605331Samw
7615331Samw *modep = mode;
7625331Samw
7635331Samw out:
7645331Samw return (error);
7655331Samw }
7665331Samw
7675331Samw static void
acevals_init(acevals_t * vals,uid_t key)7685331Samw acevals_init(acevals_t *vals, uid_t key)
7695331Samw {
7705331Samw bzero(vals, sizeof (*vals));
7715331Samw vals->allowed = ACE_MASK_UNDEFINED;
7725331Samw vals->denied = ACE_MASK_UNDEFINED;
7735331Samw vals->mask = ACE_MASK_UNDEFINED;
7745331Samw vals->key = key;
7755331Samw }
7765331Samw
7775331Samw static void
ace_list_init(ace_list_t * al,int dfacl_flag)7785331Samw ace_list_init(ace_list_t *al, int dfacl_flag)
7795331Samw {
7805331Samw acevals_init(&al->user_obj, NULL);
7815331Samw acevals_init(&al->group_obj, NULL);
7825331Samw acevals_init(&al->other_obj, NULL);
7835331Samw al->numusers = 0;
7845331Samw al->numgroups = 0;
7855331Samw al->acl_mask = 0;
7865331Samw al->hasmask = 0;
7875331Samw al->state = ace_unused;
7885331Samw al->seen = 0;
7895331Samw al->dfacl_flag = dfacl_flag;
7905331Samw }
7915331Samw
7925331Samw /*
7935331Samw * Find or create an acevals holder for a given id and avl tree.
7945331Samw *
7955331Samw * Note that only one thread will ever touch these avl trees, so
7965331Samw * there is no need for locking.
7975331Samw */
7985331Samw static acevals_t *
acevals_find(ace_t * ace,avl_tree_t * avl,int * num)7995331Samw acevals_find(ace_t *ace, avl_tree_t *avl, int *num)
8005331Samw {
8015331Samw acevals_t key, *rc;
8025331Samw avl_index_t where;
8035331Samw
8045331Samw key.key = ace->a_who;
8055331Samw rc = avl_find(avl, &key, &where);
8065331Samw if (rc != NULL)
8075331Samw return (rc);
8085331Samw
8095331Samw /* this memory is freed by ln_ace_to_aent()->ace_list_free() */
8105331Samw if (cacl_malloc((void **)&rc, sizeof (acevals_t)) != 0)
8115331Samw return (NULL);
8125331Samw
8135331Samw acevals_init(rc, ace->a_who);
8145331Samw avl_insert(avl, rc, where);
8155331Samw (*num)++;
8165331Samw
8175331Samw return (rc);
8185331Samw }
8195331Samw
8205331Samw static int
access_mask_check(ace_t * acep,int mask_bit,int isowner)8215331Samw access_mask_check(ace_t *acep, int mask_bit, int isowner)
8225331Samw {
8235331Samw int set_deny, err_deny;
8245331Samw int set_allow, err_allow;
8255331Samw int acl_consume;
8265331Samw int haswriteperm, hasreadperm;
8275331Samw
8285331Samw if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) {
8295331Samw haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 0 : 1;
8305331Samw hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 0 : 1;
8315331Samw } else {
8325331Samw haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 1 : 0;
8335331Samw hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 1 : 0;
8345331Samw }
8355331Samw
8365331Samw acl_consume = (ACL_SYNCHRONIZE_ERR_DENY |
8375331Samw ACL_DELETE_ERR_DENY |
8385331Samw ACL_WRITE_OWNER_ERR_DENY |
8395331Samw ACL_WRITE_OWNER_ERR_ALLOW |
8405331Samw ACL_WRITE_ATTRS_OWNER_SET_ALLOW |
8415331Samw ACL_WRITE_ATTRS_OWNER_ERR_DENY |
8425331Samw ACL_WRITE_ATTRS_WRITER_SET_DENY |
8435331Samw ACL_WRITE_ATTRS_WRITER_ERR_ALLOW |
8445331Samw ACL_WRITE_NAMED_WRITER_ERR_DENY |
8455331Samw ACL_READ_NAMED_READER_ERR_DENY);
8465331Samw
8475331Samw if (mask_bit == ACE_SYNCHRONIZE) {
8485331Samw set_deny = ACL_SYNCHRONIZE_SET_DENY;
8495331Samw err_deny = ACL_SYNCHRONIZE_ERR_DENY;
8505331Samw set_allow = ACL_SYNCHRONIZE_SET_ALLOW;
8515331Samw err_allow = ACL_SYNCHRONIZE_ERR_ALLOW;
8525331Samw } else if (mask_bit == ACE_WRITE_OWNER) {
8535331Samw set_deny = ACL_WRITE_OWNER_SET_DENY;
8545331Samw err_deny = ACL_WRITE_OWNER_ERR_DENY;
8555331Samw set_allow = ACL_WRITE_OWNER_SET_ALLOW;
8565331Samw err_allow = ACL_WRITE_OWNER_ERR_ALLOW;
8575331Samw } else if (mask_bit == ACE_DELETE) {
8585331Samw set_deny = ACL_DELETE_SET_DENY;
8595331Samw err_deny = ACL_DELETE_ERR_DENY;
8605331Samw set_allow = ACL_DELETE_SET_ALLOW;
8615331Samw err_allow = ACL_DELETE_ERR_ALLOW;
8625331Samw } else if (mask_bit == ACE_WRITE_ATTRIBUTES) {
8635331Samw if (isowner) {
8645331Samw set_deny = ACL_WRITE_ATTRS_OWNER_SET_DENY;
8655331Samw err_deny = ACL_WRITE_ATTRS_OWNER_ERR_DENY;
8665331Samw set_allow = ACL_WRITE_ATTRS_OWNER_SET_ALLOW;
8675331Samw err_allow = ACL_WRITE_ATTRS_OWNER_ERR_ALLOW;
8685331Samw } else if (haswriteperm) {
8695331Samw set_deny = ACL_WRITE_ATTRS_WRITER_SET_DENY;
8705331Samw err_deny = ACL_WRITE_ATTRS_WRITER_ERR_DENY;
8715331Samw set_allow = ACL_WRITE_ATTRS_WRITER_SET_ALLOW;
8725331Samw err_allow = ACL_WRITE_ATTRS_WRITER_ERR_ALLOW;
8735331Samw } else {
8745331Samw if ((acep->a_access_mask & mask_bit) &&
8755331Samw (acep->a_type & ACE_ACCESS_ALLOWED_ACE_TYPE)) {
8765331Samw return (ENOTSUP);
8775331Samw }
8785331Samw return (0);
8795331Samw }
8805331Samw } else if (mask_bit == ACE_READ_NAMED_ATTRS) {
8815331Samw if (!hasreadperm)
8825331Samw return (0);
8835331Samw
8845331Samw set_deny = ACL_READ_NAMED_READER_SET_DENY;
8855331Samw err_deny = ACL_READ_NAMED_READER_ERR_DENY;
8865331Samw set_allow = ACL_READ_NAMED_READER_SET_ALLOW;
8875331Samw err_allow = ACL_READ_NAMED_READER_ERR_ALLOW;
8885331Samw } else if (mask_bit == ACE_WRITE_NAMED_ATTRS) {
8895331Samw if (!haswriteperm)
8905331Samw return (0);
8915331Samw
8925331Samw set_deny = ACL_WRITE_NAMED_WRITER_SET_DENY;
8935331Samw err_deny = ACL_WRITE_NAMED_WRITER_ERR_DENY;
8945331Samw set_allow = ACL_WRITE_NAMED_WRITER_SET_ALLOW;
8955331Samw err_allow = ACL_WRITE_NAMED_WRITER_ERR_ALLOW;
8965331Samw } else {
8975331Samw return (EINVAL);
8985331Samw }
8995331Samw
9005331Samw if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) {
9015331Samw if (acl_consume & set_deny) {
9025331Samw if (!(acep->a_access_mask & mask_bit)) {
9035331Samw return (ENOTSUP);
9045331Samw }
9055331Samw } else if (acl_consume & err_deny) {
9065331Samw if (acep->a_access_mask & mask_bit) {
9075331Samw return (ENOTSUP);
9085331Samw }
9095331Samw }
9105331Samw } else {
9115331Samw /* ACE_ACCESS_ALLOWED_ACE_TYPE */
9125331Samw if (acl_consume & set_allow) {
9135331Samw if (!(acep->a_access_mask & mask_bit)) {
9145331Samw return (ENOTSUP);
9155331Samw }
9165331Samw } else if (acl_consume & err_allow) {
9175331Samw if (acep->a_access_mask & mask_bit) {
9185331Samw return (ENOTSUP);
9195331Samw }
9205331Samw }
9215331Samw }
9225331Samw return (0);
9235331Samw }
9245331Samw
9255331Samw static int
ace_to_aent_legal(ace_t * acep)9265331Samw ace_to_aent_legal(ace_t *acep)
9275331Samw {
9285331Samw int error = 0;
9295331Samw int isowner;
9305331Samw
9315331Samw /* only ALLOW or DENY */
9325331Samw if ((acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE) &&
9335331Samw (acep->a_type != ACE_ACCESS_DENIED_ACE_TYPE)) {
9345331Samw error = ENOTSUP;
9355331Samw goto out;
9365331Samw }
9375331Samw
9385331Samw /* check for invalid flags */
9395331Samw if (acep->a_flags & ~(ACE_VALID_FLAG_BITS)) {
9405331Samw error = EINVAL;
9415331Samw goto out;
9425331Samw }
9435331Samw
9445331Samw /* some flags are illegal */
9455331Samw if (acep->a_flags & (ACE_SUCCESSFUL_ACCESS_ACE_FLAG |
9465331Samw ACE_FAILED_ACCESS_ACE_FLAG |
9475331Samw ACE_NO_PROPAGATE_INHERIT_ACE)) {
9485331Samw error = ENOTSUP;
9495331Samw goto out;
9505331Samw }
9515331Samw
9525331Samw /* check for invalid masks */
9535331Samw if (acep->a_access_mask & ~(ACE_VALID_MASK_BITS)) {
9545331Samw error = EINVAL;
9555331Samw goto out;
9565331Samw }
9575331Samw
9585331Samw if ((acep->a_flags & ACE_OWNER)) {
9595331Samw isowner = 1;
9605331Samw } else {
9615331Samw isowner = 0;
9625331Samw }
9635331Samw
9645331Samw error = access_mask_check(acep, ACE_SYNCHRONIZE, isowner);
9655331Samw if (error)
9665331Samw goto out;
9675331Samw
9685331Samw error = access_mask_check(acep, ACE_WRITE_OWNER, isowner);
9695331Samw if (error)
9705331Samw goto out;
9715331Samw
9725331Samw error = access_mask_check(acep, ACE_DELETE, isowner);
9735331Samw if (error)
9745331Samw goto out;
9755331Samw
9765331Samw error = access_mask_check(acep, ACE_WRITE_ATTRIBUTES, isowner);
9775331Samw if (error)
9785331Samw goto out;
9795331Samw
9805331Samw error = access_mask_check(acep, ACE_READ_NAMED_ATTRS, isowner);
9815331Samw if (error)
9825331Samw goto out;
9835331Samw
9845331Samw error = access_mask_check(acep, ACE_WRITE_NAMED_ATTRS, isowner);
9855331Samw if (error)
9865331Samw goto out;
9875331Samw
9885331Samw /* more detailed checking of masks */
9895331Samw if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
9905331Samw if (! (acep->a_access_mask & ACE_READ_ATTRIBUTES)) {
9915331Samw error = ENOTSUP;
9925331Samw goto out;
9935331Samw }
9945331Samw if ((acep->a_access_mask & ACE_WRITE_DATA) &&
9955331Samw (! (acep->a_access_mask & ACE_APPEND_DATA))) {
9965331Samw error = ENOTSUP;
9975331Samw goto out;
9985331Samw }
9995331Samw if ((! (acep->a_access_mask & ACE_WRITE_DATA)) &&
10005331Samw (acep->a_access_mask & ACE_APPEND_DATA)) {
10015331Samw error = ENOTSUP;
10025331Samw goto out;
10035331Samw }
10045331Samw }
10055331Samw
10065331Samw /* ACL enforcement */
10075331Samw if ((acep->a_access_mask & ACE_READ_ACL) &&
10085331Samw (acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE)) {
10095331Samw error = ENOTSUP;
10105331Samw goto out;
10115331Samw }
10125331Samw if (acep->a_access_mask & ACE_WRITE_ACL) {
10135331Samw if ((acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) &&
10145331Samw (isowner)) {
10155331Samw error = ENOTSUP;
10165331Samw goto out;
10175331Samw }
10185331Samw if ((acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) &&
10195331Samw (! isowner)) {
10205331Samw error = ENOTSUP;
10215331Samw goto out;
10225331Samw }
10235331Samw }
10245331Samw
10255331Samw out:
10265331Samw return (error);
10275331Samw }
10285331Samw
10295331Samw static int
ace_allow_to_mode(uint32_t mask,o_mode_t * modep,int isdir)10305331Samw ace_allow_to_mode(uint32_t mask, o_mode_t *modep, int isdir)
10315331Samw {
10325331Samw /* ACE_READ_ACL and ACE_READ_ATTRIBUTES must both be set */
10335331Samw if ((mask & (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) !=
10345331Samw (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) {
10355331Samw return (ENOTSUP);
10365331Samw }
10375331Samw
10385331Samw return (ace_mask_to_mode(mask, modep, isdir));
10395331Samw }
10405331Samw
10415331Samw static int
acevals_to_aent(acevals_t * vals,aclent_t * dest,ace_list_t * list,uid_t owner,gid_t group,int isdir)10425331Samw acevals_to_aent(acevals_t *vals, aclent_t *dest, ace_list_t *list,
10435331Samw uid_t owner, gid_t group, int isdir)
10445331Samw {
10455331Samw int error;
10465331Samw uint32_t flips = ACE_POSIX_SUPPORTED_BITS;
10475331Samw
10485331Samw if (isdir)
10495331Samw flips |= ACE_DELETE_CHILD;
10505331Samw if (vals->allowed != (vals->denied ^ flips)) {
10515331Samw error = ENOTSUP;
10525331Samw goto out;
10535331Samw }
10545331Samw if ((list->hasmask) && (list->acl_mask != vals->mask) &&
10555331Samw (vals->aent_type & (USER | GROUP | GROUP_OBJ))) {
10565331Samw error = ENOTSUP;
10575331Samw goto out;
10585331Samw }
10595331Samw error = ace_allow_to_mode(vals->allowed, &dest->a_perm, isdir);
10605331Samw if (error != 0)
10615331Samw goto out;
10625331Samw dest->a_type = vals->aent_type;
10635331Samw if (dest->a_type & (USER | GROUP)) {
10645331Samw dest->a_id = vals->key;
10655331Samw } else if (dest->a_type & USER_OBJ) {
10665331Samw dest->a_id = owner;
10675331Samw } else if (dest->a_type & GROUP_OBJ) {
10685331Samw dest->a_id = group;
10695331Samw } else if (dest->a_type & OTHER_OBJ) {
10705331Samw dest->a_id = 0;
10715331Samw } else {
10725331Samw error = EINVAL;
10735331Samw goto out;
10745331Samw }
10755331Samw
10765331Samw out:
10775331Samw return (error);
10785331Samw }
10795331Samw
10805331Samw
10815331Samw static int
ace_list_to_aent(ace_list_t * list,aclent_t ** aclentp,int * aclcnt,uid_t owner,gid_t group,int isdir)10825331Samw ace_list_to_aent(ace_list_t *list, aclent_t **aclentp, int *aclcnt,
10835331Samw uid_t owner, gid_t group, int isdir)
10845331Samw {
10855331Samw int error = 0;
10865331Samw aclent_t *aent, *result = NULL;
10875331Samw acevals_t *vals;
10885331Samw int resultcount;
10895331Samw
10905331Samw if ((list->seen & (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) !=
10915331Samw (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) {
10925331Samw error = ENOTSUP;
10935331Samw goto out;
10945331Samw }
10955331Samw if ((! list->hasmask) && (list->numusers + list->numgroups > 0)) {
10965331Samw error = ENOTSUP;
10975331Samw goto out;
10985331Samw }
10995331Samw
11005331Samw resultcount = 3 + list->numusers + list->numgroups;
11015331Samw /*
11025331Samw * This must be the same condition as below, when we add the CLASS_OBJ
11035331Samw * (aka ACL mask)
11045331Samw */
11055331Samw if ((list->hasmask) || (! list->dfacl_flag))
11065331Samw resultcount += 1;
11075331Samw
11085331Samw if (cacl_malloc((void **)&result,
11095331Samw resultcount * sizeof (aclent_t)) != 0) {
11105331Samw error = ENOMEM;
11115331Samw goto out;
11125331Samw }
11135331Samw aent = result;
11145331Samw
11155331Samw /* USER_OBJ */
11165331Samw if (!(list->user_obj.aent_type & USER_OBJ)) {
11175331Samw error = EINVAL;
11185331Samw goto out;
11195331Samw }
11205331Samw
11215331Samw error = acevals_to_aent(&list->user_obj, aent, list, owner, group,
11225331Samw isdir);
11235331Samw
11245331Samw if (error != 0)
11255331Samw goto out;
11265331Samw ++aent;
11275331Samw /* USER */
11285331Samw vals = NULL;
11295331Samw for (vals = avl_first(&list->user); vals != NULL;
11305331Samw vals = AVL_NEXT(&list->user, vals)) {
11315331Samw if (!(vals->aent_type & USER)) {
11325331Samw error = EINVAL;
11335331Samw goto out;
11345331Samw }
11355331Samw error = acevals_to_aent(vals, aent, list, owner, group,
11365331Samw isdir);
11375331Samw if (error != 0)
11385331Samw goto out;
11395331Samw ++aent;
11405331Samw }
11415331Samw /* GROUP_OBJ */
11425331Samw if (!(list->group_obj.aent_type & GROUP_OBJ)) {
11435331Samw error = EINVAL;
11445331Samw goto out;
11455331Samw }
11465331Samw error = acevals_to_aent(&list->group_obj, aent, list, owner, group,
11475331Samw isdir);
11485331Samw if (error != 0)
11495331Samw goto out;
11505331Samw ++aent;
11515331Samw /* GROUP */
11525331Samw vals = NULL;
11535331Samw for (vals = avl_first(&list->group); vals != NULL;
11545331Samw vals = AVL_NEXT(&list->group, vals)) {
11555331Samw if (!(vals->aent_type & GROUP)) {
11565331Samw error = EINVAL;
11575331Samw goto out;
11585331Samw }
11595331Samw error = acevals_to_aent(vals, aent, list, owner, group,
11605331Samw isdir);
11615331Samw if (error != 0)
11625331Samw goto out;
11635331Samw ++aent;
11645331Samw }
11655331Samw /*
11665331Samw * CLASS_OBJ (aka ACL_MASK)
11675331Samw *
11685331Samw * An ACL_MASK is not fabricated if the ACL is a default ACL.
11695331Samw * This is to follow UFS's behavior.
11705331Samw */
11715331Samw if ((list->hasmask) || (! list->dfacl_flag)) {
11725331Samw if (list->hasmask) {
11735331Samw uint32_t flips = ACE_POSIX_SUPPORTED_BITS;
11745331Samw if (isdir)
11755331Samw flips |= ACE_DELETE_CHILD;
11765331Samw error = ace_mask_to_mode(list->acl_mask ^ flips,
11775331Samw &aent->a_perm, isdir);
11785331Samw if (error != 0)
11795331Samw goto out;
11805331Samw } else {
11815331Samw /* fabricate the ACL_MASK from the group permissions */
11825331Samw error = ace_mask_to_mode(list->group_obj.allowed,
11835331Samw &aent->a_perm, isdir);
11845331Samw if (error != 0)
11855331Samw goto out;
11865331Samw }
11875331Samw aent->a_id = 0;
11885331Samw aent->a_type = CLASS_OBJ | list->dfacl_flag;
11895331Samw ++aent;
11905331Samw }
11915331Samw /* OTHER_OBJ */
11925331Samw if (!(list->other_obj.aent_type & OTHER_OBJ)) {
11935331Samw error = EINVAL;
11945331Samw goto out;
11955331Samw }
11965331Samw error = acevals_to_aent(&list->other_obj, aent, list, owner, group,
11975331Samw isdir);
11985331Samw if (error != 0)
11995331Samw goto out;
12005331Samw ++aent;
12015331Samw
12025331Samw *aclentp = result;
12035331Samw *aclcnt = resultcount;
12045331Samw
12055331Samw out:
12065331Samw if (error != 0) {
12075331Samw if (result != NULL)
12085331Samw cacl_free(result, resultcount * sizeof (aclent_t));
12095331Samw }
12105331Samw
12115331Samw return (error);
12125331Samw }
12135331Samw
12145331Samw
12155331Samw /*
12165331Samw * free all data associated with an ace_list
12175331Samw */
12185331Samw static void
ace_list_free(ace_list_t * al)12195331Samw ace_list_free(ace_list_t *al)
12205331Samw {
12215331Samw acevals_t *node;
12225331Samw void *cookie;
12235331Samw
12245331Samw if (al == NULL)
12255331Samw return;
12265331Samw
12275331Samw cookie = NULL;
12285331Samw while ((node = avl_destroy_nodes(&al->user, &cookie)) != NULL)
12295331Samw cacl_free(node, sizeof (acevals_t));
12305331Samw cookie = NULL;
12315331Samw while ((node = avl_destroy_nodes(&al->group, &cookie)) != NULL)
12325331Samw cacl_free(node, sizeof (acevals_t));
12335331Samw
12345331Samw avl_destroy(&al->user);
12355331Samw avl_destroy(&al->group);
12365331Samw
12375331Samw /* free the container itself */
12385331Samw cacl_free(al, sizeof (ace_list_t));
12395331Samw }
12405331Samw
12415331Samw static int
acevals_compare(const void * va,const void * vb)12425331Samw acevals_compare(const void *va, const void *vb)
12435331Samw {
12445331Samw const acevals_t *a = va, *b = vb;
12455331Samw
12465331Samw if (a->key == b->key)
12475331Samw return (0);
12485331Samw
12495331Samw if (a->key > b->key)
12505331Samw return (1);
12515331Samw
12525331Samw else
12535331Samw return (-1);
12545331Samw }
12555331Samw
12565331Samw /*
12575331Samw * Convert a list of ace_t entries to equivalent regular and default
12585331Samw * aclent_t lists. Return error (ENOTSUP) when conversion is not possible.
12595331Samw */
12605331Samw static int
ln_ace_to_aent(ace_t * ace,int n,uid_t owner,gid_t group,aclent_t ** aclentp,int * aclcnt,aclent_t ** dfaclentp,int * dfaclcnt,int isdir)12615331Samw ln_ace_to_aent(ace_t *ace, int n, uid_t owner, gid_t group,
12625331Samw aclent_t **aclentp, int *aclcnt, aclent_t **dfaclentp, int *dfaclcnt,
12635331Samw int isdir)
12645331Samw {
12655331Samw int error = 0;
12665331Samw ace_t *acep;
12675331Samw uint32_t bits;
12685331Samw int i;
12695331Samw ace_list_t *normacl = NULL, *dfacl = NULL, *acl;
12705331Samw acevals_t *vals;
12715331Samw
12725331Samw *aclentp = NULL;
12735331Samw *aclcnt = 0;
12745331Samw *dfaclentp = NULL;
12755331Samw *dfaclcnt = 0;
12765331Samw
12775331Samw /* we need at least user_obj, group_obj, and other_obj */
12785331Samw if (n < 6) {
12795331Samw error = ENOTSUP;
12805331Samw goto out;
12815331Samw }
12825331Samw if (ace == NULL) {
12835331Samw error = EINVAL;
12845331Samw goto out;
12855331Samw }
12865331Samw
12875331Samw error = cacl_malloc((void **)&normacl, sizeof (ace_list_t));
12885331Samw if (error != 0)
12895331Samw goto out;
12905331Samw
12915331Samw avl_create(&normacl->user, acevals_compare, sizeof (acevals_t),
12925331Samw offsetof(acevals_t, avl));
12935331Samw avl_create(&normacl->group, acevals_compare, sizeof (acevals_t),
12945331Samw offsetof(acevals_t, avl));
12955331Samw
12965331Samw ace_list_init(normacl, 0);
12975331Samw
12985331Samw error = cacl_malloc((void **)&dfacl, sizeof (ace_list_t));
12995331Samw if (error != 0)
13005331Samw goto out;
13015331Samw
13025331Samw avl_create(&dfacl->user, acevals_compare, sizeof (acevals_t),
13035331Samw offsetof(acevals_t, avl));
13045331Samw avl_create(&dfacl->group, acevals_compare, sizeof (acevals_t),
13055331Samw offsetof(acevals_t, avl));
13065331Samw ace_list_init(dfacl, ACL_DEFAULT);
13075331Samw
13085331Samw /* process every ace_t... */
13095331Samw for (i = 0; i < n; i++) {
13105331Samw acep = &ace[i];
13115331Samw
13125331Samw /* rule out certain cases quickly */
13135331Samw error = ace_to_aent_legal(acep);
13145331Samw if (error != 0)
13155331Samw goto out;
13165331Samw
13175331Samw /*
13185331Samw * Turn off these bits in order to not have to worry about
13195331Samw * them when doing the checks for compliments.
13205331Samw */
13215331Samw acep->a_access_mask &= ~(ACE_WRITE_OWNER | ACE_DELETE |
13225331Samw ACE_SYNCHRONIZE | ACE_WRITE_ATTRIBUTES |
13235331Samw ACE_READ_NAMED_ATTRS | ACE_WRITE_NAMED_ATTRS);
13245331Samw
13255331Samw /* see if this should be a regular or default acl */
13265331Samw bits = acep->a_flags &
13275331Samw (ACE_INHERIT_ONLY_ACE |
13285331Samw ACE_FILE_INHERIT_ACE |
13295331Samw ACE_DIRECTORY_INHERIT_ACE);
13305331Samw if (bits != 0) {
13315331Samw /* all or nothing on these inherit bits */
13325331Samw if (bits != (ACE_INHERIT_ONLY_ACE |
13335331Samw ACE_FILE_INHERIT_ACE |
13345331Samw ACE_DIRECTORY_INHERIT_ACE)) {
13355331Samw error = ENOTSUP;
13365331Samw goto out;
13375331Samw }
13385331Samw acl = dfacl;
13395331Samw } else {
13405331Samw acl = normacl;
13415331Samw }
13425331Samw
13435331Samw if ((acep->a_flags & ACE_OWNER)) {
13445331Samw if (acl->state > ace_user_obj) {
13455331Samw error = ENOTSUP;
13465331Samw goto out;
13475331Samw }
13485331Samw acl->state = ace_user_obj;
13495331Samw acl->seen |= USER_OBJ;
13505331Samw vals = &acl->user_obj;
13515331Samw vals->aent_type = USER_OBJ | acl->dfacl_flag;
13525331Samw } else if ((acep->a_flags & ACE_EVERYONE)) {
13535331Samw acl->state = ace_other_obj;
13545331Samw acl->seen |= OTHER_OBJ;
13555331Samw vals = &acl->other_obj;
13565331Samw vals->aent_type = OTHER_OBJ | acl->dfacl_flag;
13575331Samw } else if (acep->a_flags & ACE_IDENTIFIER_GROUP) {
13585331Samw if (acl->state > ace_group) {
13595331Samw error = ENOTSUP;
13605331Samw goto out;
13615331Samw }
13625331Samw if ((acep->a_flags & ACE_GROUP)) {
13635331Samw acl->seen |= GROUP_OBJ;
13645331Samw vals = &acl->group_obj;
13655331Samw vals->aent_type = GROUP_OBJ | acl->dfacl_flag;
13665331Samw } else {
13675331Samw acl->seen |= GROUP;
13685331Samw vals = acevals_find(acep, &acl->group,
13695331Samw &acl->numgroups);
13705331Samw if (vals == NULL) {
13715331Samw error = ENOMEM;
13725331Samw goto out;
13735331Samw }
13745331Samw vals->aent_type = GROUP | acl->dfacl_flag;
13755331Samw }
13765331Samw acl->state = ace_group;
13775331Samw } else {
13785331Samw if (acl->state > ace_user) {
13795331Samw error = ENOTSUP;
13805331Samw goto out;
13815331Samw }
13825331Samw acl->state = ace_user;
13835331Samw acl->seen |= USER;
13845331Samw vals = acevals_find(acep, &acl->user,
13855331Samw &acl->numusers);
13865331Samw if (vals == NULL) {
13875331Samw error = ENOMEM;
13885331Samw goto out;
13895331Samw }
13905331Samw vals->aent_type = USER | acl->dfacl_flag;
13915331Samw }
13925331Samw
13935331Samw if (!(acl->state > ace_unused)) {
13945331Samw error = EINVAL;
13955331Samw goto out;
13965331Samw }
13975331Samw
13985331Samw if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
13995331Samw /* no more than one allowed per aclent_t */
14005331Samw if (vals->allowed != ACE_MASK_UNDEFINED) {
14015331Samw error = ENOTSUP;
14025331Samw goto out;
14035331Samw }
14045331Samw vals->allowed = acep->a_access_mask;
14055331Samw } else {
14065331Samw /*
14075331Samw * it's a DENY; if there was a previous DENY, it
14085331Samw * must have been an ACL_MASK.
14095331Samw */
14105331Samw if (vals->denied != ACE_MASK_UNDEFINED) {
14115331Samw /* ACL_MASK is for USER and GROUP only */
14125331Samw if ((acl->state != ace_user) &&
14135331Samw (acl->state != ace_group)) {
14145331Samw error = ENOTSUP;
14155331Samw goto out;
14165331Samw }
14175331Samw
14185331Samw if (! acl->hasmask) {
14195331Samw acl->hasmask = 1;
14205331Samw acl->acl_mask = vals->denied;
14215331Samw /* check for mismatched ACL_MASK emulations */
14225331Samw } else if (acl->acl_mask != vals->denied) {
14235331Samw error = ENOTSUP;
14245331Samw goto out;
14255331Samw }
14265331Samw vals->mask = vals->denied;
14275331Samw }
14285331Samw vals->denied = acep->a_access_mask;
14295331Samw }
14305331Samw }
14315331Samw
14325331Samw /* done collating; produce the aclent_t lists */
14335331Samw if (normacl->state != ace_unused) {
14345331Samw error = ace_list_to_aent(normacl, aclentp, aclcnt,
14355331Samw owner, group, isdir);
14365331Samw if (error != 0) {
14375331Samw goto out;
14385331Samw }
14395331Samw }
14405331Samw if (dfacl->state != ace_unused) {
14415331Samw error = ace_list_to_aent(dfacl, dfaclentp, dfaclcnt,
14425331Samw owner, group, isdir);
14435331Samw if (error != 0) {
14445331Samw goto out;
14455331Samw }
14465331Samw }
14475331Samw
14485331Samw out:
14495331Samw if (normacl != NULL)
14505331Samw ace_list_free(normacl);
14515331Samw if (dfacl != NULL)
14525331Samw ace_list_free(dfacl);
14535331Samw
14545331Samw return (error);
14555331Samw }
14565331Samw
14575331Samw static int
convert_ace_to_aent(ace_t * acebufp,int acecnt,int isdir,uid_t owner,gid_t group,aclent_t ** retaclentp,int * retaclcnt)14585331Samw convert_ace_to_aent(ace_t *acebufp, int acecnt, int isdir,
14595331Samw uid_t owner, gid_t group, aclent_t **retaclentp, int *retaclcnt)
14605331Samw {
14615331Samw int error = 0;
14625331Samw aclent_t *aclentp, *dfaclentp;
14635331Samw int aclcnt, dfaclcnt;
14645331Samw int aclsz, dfaclsz;
14655331Samw
14665331Samw error = ln_ace_to_aent(acebufp, acecnt, owner, group,
14675331Samw &aclentp, &aclcnt, &dfaclentp, &dfaclcnt, isdir);
14685331Samw
14695331Samw if (error)
14705331Samw return (error);
14715331Samw
14725331Samw
14735331Samw if (dfaclcnt != 0) {
14745331Samw /*
14755331Samw * Slap aclentp and dfaclentp into a single array.
14765331Samw */
14775331Samw aclsz = sizeof (aclent_t) * aclcnt;
14785331Samw dfaclsz = sizeof (aclent_t) * dfaclcnt;
14795331Samw aclentp = cacl_realloc(aclentp, aclsz, aclsz + dfaclsz);
14805331Samw if (aclentp != NULL) {
14815331Samw (void) memcpy(aclentp + aclcnt, dfaclentp, dfaclsz);
14825331Samw } else {
14835331Samw error = ENOMEM;
14845331Samw }
14855331Samw }
14865331Samw
14875331Samw if (aclentp) {
14885331Samw *retaclentp = aclentp;
14895331Samw *retaclcnt = aclcnt + dfaclcnt;
14905331Samw }
14915331Samw
14925331Samw if (dfaclentp)
14935331Samw cacl_free(dfaclentp, dfaclsz);
14945331Samw
14955331Samw return (error);
14965331Samw }
14975331Samw
14985331Samw
14995331Samw int
acl_translate(acl_t * aclp,int target_flavor,int isdir,uid_t owner,gid_t group)15005331Samw acl_translate(acl_t *aclp, int target_flavor, int isdir, uid_t owner,
15015331Samw gid_t group)
15025331Samw {
15035331Samw int aclcnt;
15045331Samw void *acldata;
15055331Samw int error;
15065331Samw
15075331Samw /*
15085331Samw * See if we need to translate
15095331Samw */
15105331Samw if ((target_flavor == _ACL_ACE_ENABLED && aclp->acl_type == ACE_T) ||
15115331Samw (target_flavor == _ACL_ACLENT_ENABLED &&
15125331Samw aclp->acl_type == ACLENT_T))
15135331Samw return (0);
15145331Samw
15155331Samw if (target_flavor == -1) {
15165331Samw error = EINVAL;
15175331Samw goto out;
15185331Samw }
15195331Samw
15205331Samw if (target_flavor == _ACL_ACE_ENABLED &&
15215331Samw aclp->acl_type == ACLENT_T) {
15225331Samw error = convert_aent_to_ace(aclp->acl_aclp,
15235331Samw aclp->acl_cnt, isdir, (ace_t **)&acldata, &aclcnt);
15245331Samw if (error)
15255331Samw goto out;
15265331Samw
15275331Samw } else if (target_flavor == _ACL_ACLENT_ENABLED &&
15285331Samw aclp->acl_type == ACE_T) {
15295331Samw error = convert_ace_to_aent(aclp->acl_aclp, aclp->acl_cnt,
15305331Samw isdir, owner, group, (aclent_t **)&acldata, &aclcnt);
15315331Samw if (error)
15325331Samw goto out;
15335331Samw } else {
15345331Samw error = ENOTSUP;
15355331Samw goto out;
15365331Samw }
15375331Samw
15385331Samw /*
15395331Samw * replace old acl with newly translated acl
15405331Samw */
15415331Samw cacl_free(aclp->acl_aclp, aclp->acl_cnt * aclp->acl_entry_size);
15425331Samw aclp->acl_aclp = acldata;
15435331Samw aclp->acl_cnt = aclcnt;
15445331Samw if (target_flavor == _ACL_ACE_ENABLED) {
15455331Samw aclp->acl_type = ACE_T;
15465331Samw aclp->acl_entry_size = sizeof (ace_t);
15475331Samw } else {
15485331Samw aclp->acl_type = ACLENT_T;
15495331Samw aclp->acl_entry_size = sizeof (aclent_t);
15505331Samw }
15515331Samw return (0);
15525331Samw
15535331Samw out:
15545331Samw
15555331Samw #if !defined(_KERNEL)
15565331Samw errno = error;
15575331Samw return (-1);
15585331Samw #else
15595331Samw return (error);
15605331Samw #endif
15615331Samw }
1562*12164SMark.Shellenbaum@Sun.COM
1563*12164SMark.Shellenbaum@Sun.COM #define SET_ACE(acl, index, who, mask, type, flags) { \
1564*12164SMark.Shellenbaum@Sun.COM acl[0][index].a_who = (uint32_t)who; \
1565*12164SMark.Shellenbaum@Sun.COM acl[0][index].a_type = type; \
1566*12164SMark.Shellenbaum@Sun.COM acl[0][index].a_flags = flags; \
1567*12164SMark.Shellenbaum@Sun.COM acl[0][index++].a_access_mask = mask; \
1568*12164SMark.Shellenbaum@Sun.COM }
1569*12164SMark.Shellenbaum@Sun.COM
1570*12164SMark.Shellenbaum@Sun.COM void
acl_trivial_access_masks(mode_t mode,uint32_t * allow0,uint32_t * deny1,uint32_t * deny2,uint32_t * owner,uint32_t * group,uint32_t * everyone)1571*12164SMark.Shellenbaum@Sun.COM acl_trivial_access_masks(mode_t mode, uint32_t *allow0, uint32_t *deny1,
1572*12164SMark.Shellenbaum@Sun.COM uint32_t *deny2, uint32_t *owner, uint32_t *group, uint32_t *everyone)
1573*12164SMark.Shellenbaum@Sun.COM {
1574*12164SMark.Shellenbaum@Sun.COM *deny1 = *deny2 = *allow0 = *group = 0;
1575*12164SMark.Shellenbaum@Sun.COM
1576*12164SMark.Shellenbaum@Sun.COM if (!(mode & S_IRUSR) && (mode & (S_IRGRP|S_IROTH)))
1577*12164SMark.Shellenbaum@Sun.COM *deny1 |= ACE_READ_DATA;
1578*12164SMark.Shellenbaum@Sun.COM if (!(mode & S_IWUSR) && (mode & (S_IWGRP|S_IWOTH)))
1579*12164SMark.Shellenbaum@Sun.COM *deny1 |= ACE_WRITE_DATA;
1580*12164SMark.Shellenbaum@Sun.COM if (!(mode & S_IXUSR) && (mode & (S_IXGRP|S_IXOTH)))
1581*12164SMark.Shellenbaum@Sun.COM *deny1 |= ACE_EXECUTE;
1582*12164SMark.Shellenbaum@Sun.COM
1583*12164SMark.Shellenbaum@Sun.COM if (!(mode & S_IRGRP) && (mode & S_IROTH))
1584*12164SMark.Shellenbaum@Sun.COM *deny2 = ACE_READ_DATA;
1585*12164SMark.Shellenbaum@Sun.COM if (!(mode & S_IWGRP) && (mode & S_IWOTH))
1586*12164SMark.Shellenbaum@Sun.COM *deny2 |= ACE_WRITE_DATA;
1587*12164SMark.Shellenbaum@Sun.COM if (!(mode & S_IXGRP) && (mode & S_IXOTH))
1588*12164SMark.Shellenbaum@Sun.COM *deny2 |= ACE_EXECUTE;
1589*12164SMark.Shellenbaum@Sun.COM
1590*12164SMark.Shellenbaum@Sun.COM if ((mode & S_IRUSR) && (!(mode & S_IRGRP) && (mode & S_IROTH)))
1591*12164SMark.Shellenbaum@Sun.COM *allow0 |= ACE_READ_DATA;
1592*12164SMark.Shellenbaum@Sun.COM if ((mode & S_IWUSR) && (!(mode & S_IWGRP) && (mode & S_IWOTH)))
1593*12164SMark.Shellenbaum@Sun.COM *allow0 |= ACE_WRITE_DATA;
1594*12164SMark.Shellenbaum@Sun.COM if ((mode & S_IXUSR) && (!(mode & S_IXGRP) && (mode & S_IXOTH)))
1595*12164SMark.Shellenbaum@Sun.COM *allow0 |= ACE_EXECUTE;
1596*12164SMark.Shellenbaum@Sun.COM
1597*12164SMark.Shellenbaum@Sun.COM *owner = ACE_WRITE_ATTRIBUTES|ACE_WRITE_OWNER|ACE_WRITE_ACL|
1598*12164SMark.Shellenbaum@Sun.COM ACE_WRITE_NAMED_ATTRS|ACE_READ_ACL|ACE_READ_ATTRIBUTES|
1599*12164SMark.Shellenbaum@Sun.COM ACE_READ_NAMED_ATTRS|ACE_SYNCHRONIZE;
1600*12164SMark.Shellenbaum@Sun.COM if (mode & S_IRUSR)
1601*12164SMark.Shellenbaum@Sun.COM *owner |= ACE_READ_DATA;
1602*12164SMark.Shellenbaum@Sun.COM if (mode & S_IWUSR)
1603*12164SMark.Shellenbaum@Sun.COM *owner |= ACE_WRITE_DATA|ACE_APPEND_DATA;
1604*12164SMark.Shellenbaum@Sun.COM if (mode & S_IXUSR)
1605*12164SMark.Shellenbaum@Sun.COM *owner |= ACE_EXECUTE;
1606*12164SMark.Shellenbaum@Sun.COM
1607*12164SMark.Shellenbaum@Sun.COM *group = ACE_READ_ACL|ACE_READ_ATTRIBUTES| ACE_READ_NAMED_ATTRS|
1608*12164SMark.Shellenbaum@Sun.COM ACE_SYNCHRONIZE;
1609*12164SMark.Shellenbaum@Sun.COM if (mode & S_IRGRP)
1610*12164SMark.Shellenbaum@Sun.COM *group |= ACE_READ_DATA;
1611*12164SMark.Shellenbaum@Sun.COM if (mode & S_IWGRP)
1612*12164SMark.Shellenbaum@Sun.COM *group |= ACE_WRITE_DATA|ACE_APPEND_DATA;
1613*12164SMark.Shellenbaum@Sun.COM if (mode & S_IXGRP)
1614*12164SMark.Shellenbaum@Sun.COM *group |= ACE_EXECUTE;
1615*12164SMark.Shellenbaum@Sun.COM
1616*12164SMark.Shellenbaum@Sun.COM *everyone = ACE_READ_ACL|ACE_READ_ATTRIBUTES| ACE_READ_NAMED_ATTRS|
1617*12164SMark.Shellenbaum@Sun.COM ACE_SYNCHRONIZE;
1618*12164SMark.Shellenbaum@Sun.COM if (mode & S_IROTH)
1619*12164SMark.Shellenbaum@Sun.COM *everyone |= ACE_READ_DATA;
1620*12164SMark.Shellenbaum@Sun.COM if (mode & S_IWOTH)
1621*12164SMark.Shellenbaum@Sun.COM *everyone |= ACE_WRITE_DATA|ACE_APPEND_DATA;
1622*12164SMark.Shellenbaum@Sun.COM if (mode & S_IXOTH)
1623*12164SMark.Shellenbaum@Sun.COM *everyone |= ACE_EXECUTE;
1624*12164SMark.Shellenbaum@Sun.COM }
1625*12164SMark.Shellenbaum@Sun.COM
1626*12164SMark.Shellenbaum@Sun.COM int
acl_trivial_create(mode_t mode,ace_t ** acl,int * count)1627*12164SMark.Shellenbaum@Sun.COM acl_trivial_create(mode_t mode, ace_t **acl, int *count)
1628*12164SMark.Shellenbaum@Sun.COM {
1629*12164SMark.Shellenbaum@Sun.COM uint32_t deny1, deny2;
1630*12164SMark.Shellenbaum@Sun.COM uint32_t allow0;
1631*12164SMark.Shellenbaum@Sun.COM uint32_t owner, group, everyone;
1632*12164SMark.Shellenbaum@Sun.COM int index = 0;
1633*12164SMark.Shellenbaum@Sun.COM int error;
1634*12164SMark.Shellenbaum@Sun.COM
1635*12164SMark.Shellenbaum@Sun.COM *count = 3;
1636*12164SMark.Shellenbaum@Sun.COM acl_trivial_access_masks(mode, &allow0, &deny1, &deny2, &owner, &group,
1637*12164SMark.Shellenbaum@Sun.COM &everyone);
1638*12164SMark.Shellenbaum@Sun.COM
1639*12164SMark.Shellenbaum@Sun.COM if (allow0)
1640*12164SMark.Shellenbaum@Sun.COM (*count)++;
1641*12164SMark.Shellenbaum@Sun.COM if (deny1)
1642*12164SMark.Shellenbaum@Sun.COM (*count)++;
1643*12164SMark.Shellenbaum@Sun.COM if (deny2)
1644*12164SMark.Shellenbaum@Sun.COM (*count)++;
1645*12164SMark.Shellenbaum@Sun.COM
1646*12164SMark.Shellenbaum@Sun.COM if ((error = cacl_malloc((void **)acl, *count * sizeof (ace_t))) != 0)
1647*12164SMark.Shellenbaum@Sun.COM return (error);
1648*12164SMark.Shellenbaum@Sun.COM
1649*12164SMark.Shellenbaum@Sun.COM if (allow0) {
1650*12164SMark.Shellenbaum@Sun.COM SET_ACE(acl, index, -1, allow0, ACE_ACCESS_ALLOWED_ACE_TYPE,
1651*12164SMark.Shellenbaum@Sun.COM ACE_OWNER);
1652*12164SMark.Shellenbaum@Sun.COM }
1653*12164SMark.Shellenbaum@Sun.COM if (deny1) {
1654*12164SMark.Shellenbaum@Sun.COM SET_ACE(acl, index, -1, deny1, ACE_ACCESS_DENIED_ACE_TYPE,
1655*12164SMark.Shellenbaum@Sun.COM ACE_OWNER);
1656*12164SMark.Shellenbaum@Sun.COM }
1657*12164SMark.Shellenbaum@Sun.COM if (deny2) {
1658*12164SMark.Shellenbaum@Sun.COM SET_ACE(acl, index, -1, deny2, ACE_ACCESS_DENIED_ACE_TYPE,
1659*12164SMark.Shellenbaum@Sun.COM ACE_GROUP|ACE_IDENTIFIER_GROUP);
1660*12164SMark.Shellenbaum@Sun.COM }
1661*12164SMark.Shellenbaum@Sun.COM
1662*12164SMark.Shellenbaum@Sun.COM SET_ACE(acl, index, -1, owner, ACE_ACCESS_ALLOWED_ACE_TYPE, ACE_OWNER);
1663*12164SMark.Shellenbaum@Sun.COM SET_ACE(acl, index, -1, group, ACE_ACCESS_ALLOWED_ACE_TYPE,
1664*12164SMark.Shellenbaum@Sun.COM ACE_IDENTIFIER_GROUP|ACE_GROUP);
1665*12164SMark.Shellenbaum@Sun.COM SET_ACE(acl, index, -1, everyone, ACE_ACCESS_ALLOWED_ACE_TYPE,
1666*12164SMark.Shellenbaum@Sun.COM ACE_EVERYONE);
1667*12164SMark.Shellenbaum@Sun.COM
1668*12164SMark.Shellenbaum@Sun.COM return (0);
1669*12164SMark.Shellenbaum@Sun.COM }
1670*12164SMark.Shellenbaum@Sun.COM
1671*12164SMark.Shellenbaum@Sun.COM /*
1672*12164SMark.Shellenbaum@Sun.COM * ace_trivial:
1673*12164SMark.Shellenbaum@Sun.COM * determine whether an ace_t acl is trivial
1674*12164SMark.Shellenbaum@Sun.COM *
1675*12164SMark.Shellenbaum@Sun.COM * Trivialness implies that the acl is composed of only
1676*12164SMark.Shellenbaum@Sun.COM * owner, group, everyone entries. ACL can't
1677*12164SMark.Shellenbaum@Sun.COM * have read_acl denied, and write_owner/write_acl/write_attributes
1678*12164SMark.Shellenbaum@Sun.COM * can only be owner@ entry.
1679*12164SMark.Shellenbaum@Sun.COM */
1680*12164SMark.Shellenbaum@Sun.COM int
ace_trivial_common(void * acep,int aclcnt,uint64_t (* walk)(void *,uint64_t,int aclcnt,uint16_t *,uint16_t *,uint32_t *))1681*12164SMark.Shellenbaum@Sun.COM ace_trivial_common(void *acep, int aclcnt,
1682*12164SMark.Shellenbaum@Sun.COM uint64_t (*walk)(void *, uint64_t, int aclcnt,
1683*12164SMark.Shellenbaum@Sun.COM uint16_t *, uint16_t *, uint32_t *))
1684*12164SMark.Shellenbaum@Sun.COM {
1685*12164SMark.Shellenbaum@Sun.COM uint16_t flags;
1686*12164SMark.Shellenbaum@Sun.COM uint32_t mask;
1687*12164SMark.Shellenbaum@Sun.COM uint16_t type;
1688*12164SMark.Shellenbaum@Sun.COM uint64_t cookie = 0;
1689*12164SMark.Shellenbaum@Sun.COM
1690*12164SMark.Shellenbaum@Sun.COM while (cookie = walk(acep, cookie, aclcnt, &flags, &type, &mask)) {
1691*12164SMark.Shellenbaum@Sun.COM switch (flags & ACE_TYPE_FLAGS) {
1692*12164SMark.Shellenbaum@Sun.COM case ACE_OWNER:
1693*12164SMark.Shellenbaum@Sun.COM case ACE_GROUP|ACE_IDENTIFIER_GROUP:
1694*12164SMark.Shellenbaum@Sun.COM case ACE_EVERYONE:
1695*12164SMark.Shellenbaum@Sun.COM break;
1696*12164SMark.Shellenbaum@Sun.COM default:
1697*12164SMark.Shellenbaum@Sun.COM return (1);
1698*12164SMark.Shellenbaum@Sun.COM
1699*12164SMark.Shellenbaum@Sun.COM }
1700*12164SMark.Shellenbaum@Sun.COM
1701*12164SMark.Shellenbaum@Sun.COM if (flags & (ACE_FILE_INHERIT_ACE|
1702*12164SMark.Shellenbaum@Sun.COM ACE_DIRECTORY_INHERIT_ACE|ACE_NO_PROPAGATE_INHERIT_ACE|
1703*12164SMark.Shellenbaum@Sun.COM ACE_INHERIT_ONLY_ACE))
1704*12164SMark.Shellenbaum@Sun.COM return (1);
1705*12164SMark.Shellenbaum@Sun.COM
1706*12164SMark.Shellenbaum@Sun.COM /*
1707*12164SMark.Shellenbaum@Sun.COM * Special check for some special bits
1708*12164SMark.Shellenbaum@Sun.COM *
1709*12164SMark.Shellenbaum@Sun.COM * Don't allow anybody to deny reading basic
1710*12164SMark.Shellenbaum@Sun.COM * attributes or a files ACL.
1711*12164SMark.Shellenbaum@Sun.COM */
1712*12164SMark.Shellenbaum@Sun.COM if ((mask & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) &&
1713*12164SMark.Shellenbaum@Sun.COM (type == ACE_ACCESS_DENIED_ACE_TYPE))
1714*12164SMark.Shellenbaum@Sun.COM return (1);
1715*12164SMark.Shellenbaum@Sun.COM
1716*12164SMark.Shellenbaum@Sun.COM /*
1717*12164SMark.Shellenbaum@Sun.COM * Delete permissions are never set by default
1718*12164SMark.Shellenbaum@Sun.COM */
1719*12164SMark.Shellenbaum@Sun.COM if (mask & (ACE_DELETE|ACE_DELETE_CHILD))
1720*12164SMark.Shellenbaum@Sun.COM return (1);
1721*12164SMark.Shellenbaum@Sun.COM /*
1722*12164SMark.Shellenbaum@Sun.COM * only allow owner@ to have
1723*12164SMark.Shellenbaum@Sun.COM * write_acl/write_owner/write_attributes/write_xattr/
1724*12164SMark.Shellenbaum@Sun.COM */
1725*12164SMark.Shellenbaum@Sun.COM if (type == ACE_ACCESS_ALLOWED_ACE_TYPE &&
1726*12164SMark.Shellenbaum@Sun.COM (!(flags & ACE_OWNER) && (mask &
1727*12164SMark.Shellenbaum@Sun.COM (ACE_WRITE_OWNER|ACE_WRITE_ACL| ACE_WRITE_ATTRIBUTES|
1728*12164SMark.Shellenbaum@Sun.COM ACE_WRITE_NAMED_ATTRS))))
1729*12164SMark.Shellenbaum@Sun.COM return (1);
1730*12164SMark.Shellenbaum@Sun.COM
1731*12164SMark.Shellenbaum@Sun.COM }
1732*12164SMark.Shellenbaum@Sun.COM return (0);
1733*12164SMark.Shellenbaum@Sun.COM }
1734*12164SMark.Shellenbaum@Sun.COM
1735*12164SMark.Shellenbaum@Sun.COM uint64_t
ace_walk(void * datap,uint64_t cookie,int aclcnt,uint16_t * flags,uint16_t * type,uint32_t * mask)1736*12164SMark.Shellenbaum@Sun.COM ace_walk(void *datap, uint64_t cookie, int aclcnt, uint16_t *flags,
1737*12164SMark.Shellenbaum@Sun.COM uint16_t *type, uint32_t *mask)
1738*12164SMark.Shellenbaum@Sun.COM {
1739*12164SMark.Shellenbaum@Sun.COM ace_t *acep = datap;
1740*12164SMark.Shellenbaum@Sun.COM
1741*12164SMark.Shellenbaum@Sun.COM if (cookie >= aclcnt)
1742*12164SMark.Shellenbaum@Sun.COM return (0);
1743*12164SMark.Shellenbaum@Sun.COM
1744*12164SMark.Shellenbaum@Sun.COM *flags = acep[cookie].a_flags;
1745*12164SMark.Shellenbaum@Sun.COM *type = acep[cookie].a_type;
1746*12164SMark.Shellenbaum@Sun.COM *mask = acep[cookie++].a_access_mask;
1747*12164SMark.Shellenbaum@Sun.COM
1748*12164SMark.Shellenbaum@Sun.COM return (cookie);
1749*12164SMark.Shellenbaum@Sun.COM }
1750*12164SMark.Shellenbaum@Sun.COM
1751*12164SMark.Shellenbaum@Sun.COM int
ace_trivial(ace_t * acep,int aclcnt)1752*12164SMark.Shellenbaum@Sun.COM ace_trivial(ace_t *acep, int aclcnt)
1753*12164SMark.Shellenbaum@Sun.COM {
1754*12164SMark.Shellenbaum@Sun.COM return (ace_trivial_common(acep, aclcnt, ace_walk));
1755*12164SMark.Shellenbaum@Sun.COM }
1756