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 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 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 * 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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